{"server":"com.kernelcad/kernelcad","count":50,"changes":[{"tool":"run_fea","kind":"changed","observed_at":"2026-10-19T20:35:32.750Z","fields":["inputSchema"],"description_before":null,"description_after":null,"description_similarity":null,"before_hash":"754e59fcf7b30b7753befe53eb13c15b","after_hash":"88c9bacaabc06924ae6fac5c83f71925"},{"tool":"resolve_assumptions","kind":"changed","observed_at":"2026-10-19T20:35:32.750Z","fields":["inputSchema"],"description_before":null,"description_after":null,"description_similarity":null,"before_hash":"e9f27a60ac8371f760fb232638cc3a29","after_hash":"158fb6b6a1fbb06c50c69e562f2f7aba"},{"tool":"add_mate","kind":"changed","observed_at":"2026-10-19T20:35:32.750Z","fields":["inputSchema"],"description_before":null,"description_after":null,"description_similarity":null,"before_hash":"8fe8029c6017cab76ac11f00822786c5","after_hash":"3a8f3f6703dcdc006ceb77277ca3208b"},{"tool":"query","kind":"changed","observed_at":"2026-10-19T20:35:32.750Z","fields":["inputSchema"],"description_before":null,"description_after":null,"description_similarity":null,"before_hash":"31fcaa46208a9d984811fb56d5a072ec","after_hash":"efd751cf8ad48515fdf7d30ba3dee42b"},{"tool":"trace_from_image","kind":"changed","observed_at":"2026-10-19T20:35:32.750Z","fields":["inputSchema"],"description_before":null,"description_after":null,"description_similarity":null,"before_hash":"a8079b43e6422979f52b3725ed670de8","after_hash":"6eacff728fcd606c4f5ed2f4a5824f47"},{"tool":"verify","kind":"changed","observed_at":"2026-10-19T20:35:32.750Z","fields":["inputSchema"],"description_before":null,"description_after":null,"description_similarity":null,"before_hash":"d32f704f6bf6e356df42d55df80078cf","after_hash":"5160e753d5371f4d65fb199ec337019a"},{"tool":"inspect","kind":"changed","observed_at":"2026-10-19T20:35:32.750Z","fields":["inputSchema"],"description_before":null,"description_after":null,"description_similarity":null,"before_hash":"925a1b39942a21f9e1645048e1186096","after_hash":"4e5740b3127eff339fbe3a638ff99274"},{"tool":"fab_pack","kind":"changed","observed_at":"2026-10-18T20:28:53.400Z","fields":["description","inputSchema"],"description_before":"Use this when the user wants to get a part made: packages the fabrication files into one directory plus a zip, and returns links to public instant-quote pages. Pass { file | code } and output_dir; optional name (default 'part'), formats (default step, stl, 3mf, pdf-drawing, bom-csv; add 'dxf' for flat or sheet parts), and processes ('3d-print' | 'cnc' | 'sheet-cut') to filter the links. Each file is written by the export tool, so its gates apply; a format that fails is reported in files[] and the rest still ship. Also writes manifest.json and README.txt. quote_links lists JLC3DP, JLCCNC, PCBWay, Xometry, SendCutSend and Craftcloud with the pack file to upload to each. These are plain web pages: nothing is uploaded or ordered. The user opens the link and uploads the file. Run dfm_review first if you have not.\nHosted server: pack files are written on the kernelCAD server and returned in downloads[].url; nothing is uploaded to a fabrication service.","description_after":"Use this when the user wants to get a part made: packages the fabrication files into one directory plus a zip, and returns links to public instant-quote pages. Pass { file | code } and output_dir; optional scope ('part', default — one script's files; 'bom' — the whole assembly's BOM: per-part single-body files, per-part drawings, bom.csv/json and vendor handoff texts), name (default 'part'), formats (default step, stl, 3mf, pdf-drawing, bom-csv; add 'dxf' for flat or sheet parts), and processes ('3d-print' | 'cnc' | 'sheet-cut') to filter the links (bom: also narrows which fabricated rows are packed). Each file is written by the export tool, so its gates apply; a format that fails is reported in files[] and the rest still ship. Also writes manifest.json and README.txt. quote_links lists JLC3DP, JLCCNC, PCBWay, Xometry, SendCutSend and Craftcloud with the pack file to upload to each. One body per file: multi-body files are rejected by every shop. DXF is written only for flat or sheet-metal parts. The McMaster handoff text carries part numbers only, because McMaster quantities are packs and pack sizes are not in the catalog yet. These are plain web pages: nothing is uploaded or ordered. The user opens the link and uploads the file. Run dfm_review first if you have not.\nHosted server: pack files are written on the kernelCAD server and returned in downloads[].url; nothing is uploaded to a fabrication service.","description_similarity":0.777,"before_hash":"8f71473c7f97138b3a0a96441f981d68","after_hash":"22f670f6f32d857c094fa371df03b82c"},{"tool":"export","kind":"changed","observed_at":"2026-10-18T20:28:53.400Z","fields":["description","inputSchema"],"description_before":"Use this when you need to export geometry to a file. One exporter, selected by `target`:\n- target:'model' — export the script geometry to one file. Pass { file | code }, a required { output_path }, and { format }. Supported formats: stl (binary STL mesh), step (BREP CAD interchange), dxf (2D cut file for laser / waterjet / CNC: a flat part — plate, panel, extruded profile, in any orientation — exports its outline and holes in its own plane with exact arcs and circles; a sheet-metal part or a returned Region exports its flat pattern; a flat or sheet-metal part also returns sheet { thickness_mm, bend_count }, which a shop needs and the DXF does not carry; options.section { axis: \"x\"|\"y\"|\"z\", at } exports the cross-section of any part in world coordinates (plans, profiles); a multi-part model (cut list) writes all parts side by side on output_path, one layer per part, plus parts/<part>.dxf per part (reported in part_files; options.layout 'sheet' writes the combined sheet only); any other part fails with export.dxf.non-planar), 3mf (slicer-friendly mesh: one named object per part, colours as core-spec basematerials named by the part's engineering material; options.arrange 'plate' packs parts on the bed at Z=0 without overlap (options.orient puts each part's largest flat face down), 'assembled' keeps them together as one multi-part object for multi-colour prints; options.slicer 'bambu' | 'orca' | 'prusa' adds that slicer's per-object name + filament-slot sidecar — slot N is the Nth distinct colour/material), options.infill { fromFea: '<study>' | true, bands?, pattern? } = stress-graded FDM infill (requires the local CalculiX + gmsh toolchain; without it the export fails with fea.solver.unavailable): solves the feaStudy and writes modifier volumes, each with its own infill density (Orca/Bambu format by default; options.slicer 'prusa' writes PrusaSlicer's format instead, since the two are not interchangeable); the result carries infill { bands, saving, images }), gcode (installed OrcaSlicer output; preserves G-code and returns optional gcode_stats with header generator identity and slicer-predicted time/material), glb (web-viewer / AR with PBR materials), obj (Wavefront indexed triangle mesh), usd (ASCII USDA triangle mesh in millimeter, Z-up coordinates; multi-part scenes emit one named mesh per part), svg-drawing (third-angle engineering-drawing sheet: front/top/left + isometric views, hidden edges dashed, tangent edges thin, overall bounding-box dimensions, title block; assemblies are drawn with inter-part occlusion; pass options.annotations to dimension specific features instead of the bounding box; pass options.exploded { factor, mode } to explode the isometric cell, options.balloons to number parts from the BOM, and options.partsList for an item/name/qty/material table above the title block). overall bounding-box dimensions, title block; assemblies are drawn with inter-part occlusion; pass options.annotations to dimension specific features instead of the bounding box, options.autoAnnotate to derive datums A/B/C, grouped hole callouts with position tolerances, hole positions, overall size, radius and chamfer callouts, flatness and an ISO 2768 note from the geometry (the result carries drawing_report with placed / overlapped counts), and options.sections for real section views on any cutting plane). pdf-drawing (the same sheet — views, dashed hidden lines, dimensions, hole callouts, GD&T, sections, parts list — as a printable vector PDF on a standard sheet, one call: ISO a4|a3|a2|a1|a0 or ANSI ansi-a…ansi-e landscape, default a3, or sheet \"auto\" / \"auto-ansi\" for the smallest sheet that holds the views at 1:1; the drawing scale is picked to fit; projection \"third\" (default) or \"first\" arranges the views and draws the matching symbol; a full title block carries title, part name, material, scale, units, sheet size, date and revision, settable through options.title / partName / material / revision / date; autoAnnotate is on unless o","description_after":"Use this when you need to export geometry to a file. One exporter, selected by `target`:\n- target:'model' — export the script geometry to one file. Pass { file | code }, a required { output_path }, and { format }. Supported formats: stl (binary STL mesh), step (BREP CAD interchange), dxf (2D cut file for laser / waterjet / CNC: a flat part — plate, panel, extruded profile, in any orientation — exports its outline and holes in its own plane with exact arcs and circles; a sheet-metal part or a returned Region exports its flat pattern; a flat or sheet-metal part also returns sheet { thickness_mm, bend_count }, which a shop needs and the DXF does not carry; options.section { axis: \"x\"|\"y\"|\"z\", at } exports the cross-section of any part in world coordinates (plans, profiles); a multi-part model (cut list) writes all parts side by side on output_path, one layer per part, plus parts/<part>.dxf per part (reported in part_files; options.layout 'sheet' writes the combined sheet only); any other part fails with export.dxf.non-planar), 3mf (slicer-friendly mesh: one named object per part, colours as core-spec basematerials named by the part's engineering material; options.arrange 'plate' packs parts on the bed at Z=0 without overlap (options.orient puts each part's largest flat face down), 'assembled' keeps them together as one multi-part object for multi-colour prints; options.slicer 'bambu' | 'orca' | 'prusa' adds that slicer's per-object name + filament-slot sidecar — slot N is the Nth distinct colour/material), options.infill { fromFea: '<study>' | true, bands?, pattern? } = stress-graded FDM infill (requires the local CalculiX + gmsh toolchain; without it the export fails with fea.solver.unavailable): solves the feaStudy and writes modifier volumes, each with its own infill density (Orca/Bambu format by default; options.slicer 'prusa' writes PrusaSlicer's format instead, since the two are not interchangeable); the result carries infill { bands, saving, images }), gcode (installed OrcaSlicer output; preserves G-code and returns optional gcode_stats with header generator identity and slicer-predicted time/material), glb (web-viewer / AR with PBR materials), obj (Wavefront indexed triangle mesh), usd (ASCII USDA triangle mesh in millimeter, Z-up coordinates; multi-part scenes emit one named mesh per part), svg-drawing (third-angle engineering-drawing sheet: front/top/left + isometric views, hidden edges dashed, tangent edges thin, overall bounding-box dimensions, title block; assemblies are drawn with inter-part occlusion; pass options.annotations to dimension specific features instead of the bounding box; pass options.exploded { factor, mode } to explode the isometric cell, options.balloons to number parts from the BOM, and options.partsList for an item/name/qty/material table above the title block). overall bounding-box dimensions, title block; assemblies are drawn with inter-part occlusion; pass options.annotations to dimension specific features instead of the bounding box, options.autoAnnotate to derive datums A/B/C, grouped hole callouts with position tolerances, hole positions, overall size, radius and chamfer callouts, flatness and an ISO 2768 note from the geometry (the result carries drawing_report with placed / overlapped counts), and options.sections for real section views on any cutting plane). pdf-drawing (the same sheet — views, dashed hidden lines, dimensions, hole callouts, GD&T, sections, parts list — as a printable vector PDF on a standard sheet, one call: ISO a4|a3|a2|a1|a0 or ANSI ansi-a…ansi-e landscape, default a3, or sheet \"auto\" / \"auto-ansi\" for the smallest sheet that holds the views at 1:1; the drawing scale is picked to fit; projection \"third\" (default) or \"first\" arranges the views and draws the matching symbol; a full title block carries title, part name, material, scale, units, sheet size, date and revision, settable through options.title / partName / material / revision / date; autoAnnotate is on unless o","description_similarity":0.954,"before_hash":"062570dfa52d17a58572323282fbbfe5","after_hash":"6a99f6756946f9b125f41bc471014f5c"},{"tool":"inspect","kind":"changed","observed_at":"2026-10-18T20:28:53.400Z","fields":["description"],"description_before":"Use this when you need to read facts about a model. One reader, selected by `of`:\n- 'assembly' — physical assembly inventory (parts, bboxes, connectors, mates, disconnected solids).\n- 'robot' — URDF/SDFormat export preview (links, joints, planning groups, end-effectors, issues).\n- 'step' — inspect an imported STEP file: solid tree, exact bbox/volume, cylindrical holes (breached bores flagged partial; holeDetection: 'exact' | 'heuristic').\n- 'shape' — volume / surfaceArea / bbox for one feature ({ feature_id? }).\n- 'mass' — mass, centre of mass, centroidal inertia tensor (inertia6 + 3x3 inertiaMatrix), principalMoments/principalAxes, symmetry flags, and optionally the radius of gyration about an arbitrary axis ({ feature_id?, density?, gyration_axis? }); density in kg/m^3, defaults to 1000 (water).\n- 'features' — features captured by the script (kind, id, params, transforms, suppression).\n- 'assemblies' — assembly intent (assemblies, parts, connectors, joints).\n- 'topology' — canonical face names + edge count for a feature ({ feature_id? }).\n- 'edges' — edges of a shape with optional EdgeQuery ({ feature_id?, query? }); returns @kc[...] refs.\n- 'face-edges' — boundary edges of a named canonical face ({ feature_id?, face_name }).\n- 'faces' — faces of a shape with optional FaceQuery ({ feature_id?, query? }); returns @kc[...] refs.\n- 'face-labels' — user-applied labels visible in the script.\n- 'mates' — mates captured by the script.\n- 'constraints' — sketch constraints captured by the script.\n- 'part-stats' — bundled parts-catalog statistics.\n- 'bend-table' — sheet-metal bend table for a flattened pattern.\n- 'params' — declared model parameters.\n- 'part-categories' — top-level part-catalog categories available in the bundled (and configured remote) catalog.\n- 'part-families' — part families within a category ({ category? }); count + exemplar ids per family.\n- 'bom' — bill of materials ({ assembly? }): one row per distinct part (grouped by geometry/catalog identity, not name) with real instance quantity, kind ('fabricated'|'purchased'), material, density, per-unit and total mass, bbox, a fabrication process hint, catalog provenance for purchased parts, and totals; `bom.*` diagnostics flag rows with no density source or missing catalog vendor info instead of guessing.\n- 'section' — numeric cross-section probe of a shape: area, perimeter, loop/hole counts, 2D bbox at a plane ({ feature_id?, plane | at+axis, stack?: { from, to, count, axis? } }). `stack` scans evenly spaced slices and returns `minAreaIndex`/`minAreaPosition` — use it to find the neck/thinnest cross-section along an axis.\n- 'continuity' — G0/G1/G2 classification of shared edges ({ feature_id?, edges? }); position gap, normal jump, curvature difference, worst-sample XYZ.\n- 'curvature' — per-face Gaussian and mean curvature min/max/mean, inflections, spikes ({ feature_id?, faces?, spike_factor? }).\n- 'multi-material' — explicit material leaves shadowed by later attributed boolean descendants, with assembly-part rewrite templates; analyzes capture records and does not change mesh attribution.\nAll params except `of` are subject-specific and forwarded verbatim. Most subjects accept { file | code }. Hosted: give the file as an https:// URL, a data: URI (base64, max 25 MB) or \"asset:<id>\" from request_upload (when the file is on the user's device).","description_after":"Use this when you need to read facts about a model. One reader, selected by `of`:\n- 'assembly' — physical assembly inventory (parts, bboxes, connectors, mates, disconnected solids).\n- 'robot' — URDF/SDFormat export preview (links, joints, planning groups, end-effectors, issues).\n- 'step' — inspect an imported STEP file: solid tree, exact bbox/volume, cylindrical holes (breached bores flagged partial; holeDetection: 'exact' | 'heuristic').\n- 'shape' — volume / surfaceArea / bbox for one feature ({ feature_id? }).\n- 'mass' — mass, centre of mass, centroidal inertia tensor (inertia6 + 3x3 inertiaMatrix), principalMoments/principalAxes, symmetry flags, and optionally the radius of gyration about an arbitrary axis ({ feature_id?, density?, gyration_axis? }); density in kg/m^3, defaults to 1000 (water).\n- 'features' — features captured by the script (kind, id, params, transforms, suppression).\n- 'assemblies' — assembly intent (assemblies, parts, connectors, joints).\n- 'topology' — canonical face names + edge count for a feature ({ feature_id? }).\n- 'edges' — edges of a shape with optional EdgeQuery ({ feature_id?, query? }); returns @kc[...] refs.\n- 'face-edges' — boundary edges of a named canonical face ({ feature_id?, face_name }).\n- 'faces' — faces of a shape with optional FaceQuery ({ feature_id?, query? }); returns @kc[...] refs.\n- 'face-labels' — user-applied labels visible in the script.\n- 'mates' — mates captured by the script.\n- 'constraints' — sketch constraints captured by the script.\n- 'part-stats' — bundled parts-catalog statistics.\n- 'bend-table' — sheet-metal bend table for a flattened pattern.\n- 'params' — declared model parameters.\n- 'part-categories' — top-level part-catalog categories available in the bundled (and configured remote) catalog.\n- 'part-families' — part families within a category ({ category? }); count + exemplar ids per family.\n- 'bom' — bill of materials ({ assembly? }): one row per distinct part (grouped by geometry/catalog identity, not name) with real instance quantity, kind ('fabricated'|'purchased'), material, density, per-unit and total mass, bbox, a fabrication process (`process` + `processSource`), catalog provenance for purchased parts, and totals; `bom.*` diagnostics flag rows with no density source or missing catalog vendor info instead of guessing.\n- 'section' — numeric cross-section probe of a shape: area, perimeter, loop/hole counts, 2D bbox at a plane ({ feature_id?, plane | at+axis, stack?: { from, to, count, axis? } }). `stack` scans evenly spaced slices and returns `minAreaIndex`/`minAreaPosition` — use it to find the neck/thinnest cross-section along an axis.\n- 'continuity' — G0/G1/G2 classification of shared edges ({ feature_id?, edges? }); position gap, normal jump, curvature difference, worst-sample XYZ.\n- 'curvature' — per-face Gaussian and mean curvature min/max/mean, inflections, spikes ({ feature_id?, faces?, spike_factor? }).\n- 'multi-material' — explicit material leaves shadowed by later attributed boolean descendants, with assembly-part rewrite templates; analyzes capture records and does not change mesh attribution.\nAll params except `of` are subject-specific and forwarded verbatim. Most subjects accept { file | code }. Hosted: give the file as an https:// URL, a data: URI (base64, max 25 MB) or \"asset:<id>\" from request_upload (when the file is on the user's device).","description_similarity":0.993,"before_hash":"e6640a592211dd27c6a214438a489889","after_hash":"925a1b39942a21f9e1645048e1186096"},{"tool":"evaluate_script","kind":"changed","observed_at":"2026-10-18T03:11:35.404Z","fields":["description"],"description_before":"Use this when you need to run a script and check it compiles. Full local builds return viewerUrl: a live Studio link reused and updated on later full builds in the same MCP process. Hosted builds return viewerMode: hosted and viewerHint pointing to open_in_studio; they do not start a loopback viewer. Full evaluations return step evidence: build validity, volume and before/after local PNG paths in one shared iso frame. Snapshots require PW_CDP_URL for an existing browser; unavailable captures report an explicit error. Run a kernelCAD .kcad.ts script and report pass/fail + feature count + diagnostics + sceneSummary (BREP validity, volume in mm³, face count, bounding size in mm). When the scene is assembly-built (assembly().part(...) → .model()/.solvedModel()), also returns a parts summary { count, names } AND runs the mechanism-truth gate by default: the `mechanism` field reports real/broken/unverified and a broken mechanism (disconnected components / mechanism.orphan-part, self-collision, fastened drift, dof-mismatch) makes ok:false with the failures in diagnostics — a mechanism (any mate or joint) needs every part linked by connectors + mates/joints (axis+revolute for shafts/hinges/gears; frame+fastened for rigid; or arm.revolute/.prismatic/.ball/.fixed). A plain multi-part assembly with no mates (base + lid, print layout) is independent bodies and passes. Pass { skipMechanismCheck: true } to opt out (e.g. a deliberately free part next to a mechanism). An animation or drive on a fastened joint (mechanism.motion-on-fixed-joint) is broken: animate a revolute/prismatic mate pose. For a model with moving joints or motion intent, `mechanismSummary.statement` is one plain line: \"Motion checked: ...\" names what ran; \"Motion not checked: ...\" is NOT a pass — never call that mechanism working. Every union() is checked too (no opt-out): union.disconnected (the union is several separate solids — a floating operand) and union.member-overlap (two operands that each carry their own .finish()/.material(), the same one, share > 1 mm³ — cut members to fit, e.g. a cross tube between rails is span minus two rail widths) make ok:false. Pass either { file: \"<path>\" } or { code: \"<inline source>\" }. Set { dryRun: true } for fast validation while iterating: transpile + capture + capture-light checks without building solids, DFM gates, or meshing — milliseconds instead of seconds (100x+ on boolean/fillet-heavy scripts). A dry run catches script throws, capture-time API misuse, and assembly validity-gate failures, but NOT lowering failures or dfmSpec diagnostics; it leaves the active session untouched, so finish with a full (non-dry) evaluate_script before using session-dependent tools. To show a measurement in the 3D viewer (e.g. hole spacing), declare it in the script with shape.dimension({ kind: \"linear\", from, to, label }); a full evaluate lists them as dimensions: [{ text, kind, source }], and a shared /p link with ?dims=1 forces them on. Hosted: lib.fromSTEP / fromSTL / fromDXF / fromSVG and referenceImage take a direct string literal or a const bound to one (computed expressions are unsupported). They accept \"asset:<id>\" (from request_upload), an https:// URL or a data: URI as the path.","description_after":"Use this when you need to run a script and check it compiles. Full local builds return viewerUrl: a live Studio link reused and updated on later full builds in the same MCP process. Hosted builds return viewerMode: hosted and viewerHint pointing to open_in_studio; they do not start a loopback viewer. Full evaluations return step evidence: build validity, volume and before/after local PNG paths in one shared iso frame. Snapshots require PW_CDP_URL for an existing browser; unavailable captures report an explicit error. Run a kernelCAD .kcad.ts script and report pass/fail + feature count + diagnostics + sceneSummary (BREP validity, volume in mm³, face count, bounding size in mm). When the scene is assembly-built (assembly().part(...) → .model()/.solvedModel()), also returns a parts summary { count, names } AND runs the mechanism-truth gate by default: the `mechanism` field reports real/broken/unverified and a broken mechanism (disconnected components / mechanism.orphan-part, self-collision, fastened drift, dof-mismatch) makes ok:false with the failures in diagnostics, as does a mate connector more than 6 mm outside its part bounding box (assembly.mechanical.connector-not-in-solid, the same error review_cad reports) — a mechanism (any mate or joint) needs every part linked by connectors + mates/joints (axis+revolute for shafts/hinges/gears; frame+fastened for rigid; or arm.revolute/.prismatic/.ball/.fixed). A plain multi-part assembly with no mates (base + lid, print layout) is independent bodies and passes. Pass { skipMechanismCheck: true } to opt out (e.g. a deliberately free part next to a mechanism). An animation or drive on a fastened joint (mechanism.motion-on-fixed-joint) is broken: animate a revolute/prismatic mate pose. For a model with moving joints or motion intent, `mechanismSummary.statement` is one plain line: \"Motion checked: ...\" names what ran; \"Motion not checked: ...\" is NOT a pass — never call that mechanism working. Every union() is checked too (no opt-out): union.disconnected (the union is several separate solids — a floating operand) and union.member-overlap (two operands that each carry their own .finish()/.material(), the same one, share > 1 mm³ — cut members to fit, e.g. a cross tube between rails is span minus two rail widths) make ok:false. Pass either { file: \"<path>\" } or { code: \"<inline source>\" }. Set { dryRun: true } for fast validation while iterating: transpile + capture + capture-light checks without building solids, DFM gates, or meshing — milliseconds instead of seconds (100x+ on boolean/fillet-heavy scripts). A dry run catches script throws, capture-time API misuse, and assembly validity-gate failures, but NOT lowering failures or dfmSpec diagnostics; it leaves the active session untouched, so finish with a full (non-dry) evaluate_script before using session-dependent tools. To show a measurement in the 3D viewer (e.g. hole spacing), declare it in the script with shape.dimension({ kind: \"linear\", from, to, label }); a full evaluate lists them as dimensions: [{ text, kind, source }], and a shared /p link with ?dims=1 forces them on. Hosted: lib.fromSTEP / fromSTL / fromDXF / fromSVG and referenceImage take a direct string literal or a const bound to one (computed expressions are unsupported). They accept \"asset:<id>\" (from request_upload), an https:// URL or a data: URI as the path.","description_similarity":0.962,"before_hash":"04d61ad8522fc7162937f0b562714bf3","after_hash":"d022f04ff855f8de94bf298c61bb696e"},{"tool":"execute_cookbook","kind":"changed","observed_at":"2026-10-17T14:37:32.928Z","fields":["inputSchema"],"description_before":null,"description_after":null,"description_similarity":null,"before_hash":"88f0b07ffbe1d0f45835f8ecf82528c1","after_hash":"c7b2434ebad0b6b7df51bdc07b421c1b"},{"tool":"verify","kind":"changed","observed_at":"2026-10-17T14:37:32.928Z","fields":["description","inputSchema"],"description_before":"Use this when you need to check a design against a rule set. One verifier, selected by `check`:\n- 'assembly' — static assembly review ({ file | code }, or the session evaluate_script left): mate validator, default-pose interference, joint topology, mechanical plausibility. ok:false with `blocking[]` exactly when review_cad's blocking rules fire on these findings; review_cad also sweeps joint ranges and runs physics.\n- 'urdf' — structural validity of a .urdf file ({ urdf_path }).\n- 'dfm' — print-readiness gates declared by dfmSpec() ({ file | code }).\n- 'dfm-preflight' — sheet-metal flat pattern vs a job-shop's ordering rules ({ vendor, material, thicknessIn|thicknessMm, ... }). Returns the vendor's catalog source pages as `sources`; when `disclosure` is present, show it with those links.\n- 'assembly-path' — continuous straight-line removal of each assembly part along ±X/±Y/±Z and optional world-space directions. Returns valid directions and blocking parts; disassemblyOrder runs a deterministic greedy removal pass. Watertight mesh approximation, conservative contact, no rotation/mate/hardware certification.\n- 'swept-collision' — sweep declared joint range(s) and report colliding poses.\n- 'reachable' — inverse-kinematics reachability for an end-effector ({ tip_link, target_position, ... }).\n- 'geometry-quality' — one solid body's BREP tiny faces and short edges (ids, locations, mm²/mm), plus sampled mirror symmetry about centroid XY/YZ/XZ and principal inertia planes ({ file | code, feature_id?, tiny_face_area_mm2?, tiny_face_relative?, short_edge_length_mm?, symmetry_tolerance_mm?, mesh_deflection_mm?, asserted_plane?: { origin, normal } }). Relative area is a fraction of total surface area; thresholds are ORed. Candidate planes are discovery; only an asserted plane gates symmetry. Approximate sampled tessellation, not exact BREP proof.\n- 'fastener-installation' — measured explicit catalog-screw installation stations on lowered assembly BREP ({ file | code, fasteners:[{ part, against, engagementPart?, minEngagementMm?, maxProtrusionMm? }], toleranceMm?, angleToleranceDeg? }). Reports annular bearing gap, bore axis/diameter/overlap and receiver geometric engagement/protrusion. Unknown or zero coverage cannot pass. Simplified threads do not certify torque, preload or strength.\n- 'mounting-holes' — fastened mates: hole pairs one screw can use (equal, or clearance over a tap drill / hole({ thread }) of the same metric size; hole-free faces are a rigid bond) and fastener holes meeting at the contact face are coaxial. Sides it cannot resolve are info, never mismatches.\n- 'load-capacity' — will it hold? Closed-form Euler-Bernoulli beam check ({ loads, materials, ... }), or mode:'fea' to solve the script's feaStudy (quadratic-tet FEA, CalculiX) — both return { ok, safetyFactor, elements[{ partName, stressPa, yieldPa, safetyFactor }], failures[], diagnostics }; fea adds the threshold, the stress regions as @kc[...] faces with their location, and fea { peakStressPa, maxDisplacementMm, meshTrusted, peakAtSupportPa, refinement }; it refines the mesh automatically until the stress is trusted (refine: false for one solve).\n- 'static-hold' — gravitational holding torque/force at a sampled pose grid vs each actuated joint's declared actuator capacity ({ joint?, pose?, gravity?, min_torque_margin_pct?, range_samples? }).\n- 'body-likeness' — publish gate for organic/car bodies: cheap AABB↔wheel checks plus required agent still verdicts (side-body-over-wheels, side-cabin-aft, rear-haunch, ortho-proportions-vs-reference). Pass { body_bbox | code/file+body_feature_id, wheels?, cabin_bbox?, still_verdicts?, require_stills? }. Full CV silhouette matching is NOT implemented — agents must inspect ortho PNGs/Studio and supply still_verdicts before claiming success.\n- 'edge-radius' — general edge-break specification on final BREP ({ file | code, min_radius_mm?, max_radius_mm?, require_edge_break?: 'external'|'internal'|'all', feature_id?, assembly?, part","description_after":"Use this when you need to check a design against a rule set. One verifier, selected by `check`:\n- 'assembly' — static assembly review ({ file | code }, or the session evaluate_script left): mate validator, default-pose interference, joint topology, mechanical plausibility. ok:false with `blocking[]` exactly when review_cad's blocking rules fire on these findings; review_cad also sweeps joint ranges and runs physics.\n- 'urdf' — structural validity of a .urdf file ({ urdf_path }).\n- 'dfm' — print-readiness gates declared by dfmSpec() ({ file | code }).\n- 'dfm-preflight' — sheet-metal flat pattern vs a job-shop's ordering rules ({ vendor, material, thicknessIn|thicknessMm, ... }). Returns the vendor's catalog source pages as `sources`; when `disclosure` is present, show it with those links.\n- 'assembly-path' — continuous straight-line removal of each assembly part along ±X/±Y/±Z and optional world-space directions. Returns valid directions and blocking parts; disassemblyOrder runs a deterministic greedy removal pass. Watertight mesh approximation, conservative contact, no rotation/mate/hardware certification.\n- 'swept-collision' — sweep declared joint range(s) and report colliding poses.\n- 'reachable' — inverse-kinematics reachability for an end-effector ({ tip_link, target_position, ... }).\n- 'geometry-quality' — one solid body's BREP tiny faces and short edges (ids, locations, mm²/mm), plus sampled mirror symmetry about centroid XY/YZ/XZ and principal inertia planes ({ file | code, feature_id?, tiny_face_area_mm2?, tiny_face_relative?, short_edge_length_mm?, symmetry_tolerance_mm?, mesh_deflection_mm?, asserted_plane?: { origin, normal } }). Relative area is a fraction of total surface area; thresholds are ORed. Candidate planes are discovery; only an asserted plane gates symmetry. Approximate sampled tessellation, not exact BREP proof.\n- 'fastener-installation' — measured explicit catalog-screw installation stations on lowered assembly BREP ({ file | code, fasteners:[{ part, against, engagementPart?, minEngagementMm?, maxProtrusionMm? }], toleranceMm?, angleToleranceDeg? }). Reports annular bearing gap, bore axis/diameter/overlap and receiver geometric engagement/protrusion. Unknown or zero coverage cannot pass. Simplified threads do not certify torque, preload or strength.\n- 'mounting-holes' — fastened mates: hole pairs one screw can use (equal, or clearance over a tap drill / hole({ thread }) of the same metric size; hole-free faces are a rigid bond) and fastener holes meeting at the contact face are coaxial. Sides it cannot resolve are info, never mismatches.\n- 'load-capacity' — will it hold? Closed-form Euler-Bernoulli beam check ({ loads, materials, ... }), or mode:'fea' to solve the script's feaStudy (quadratic-tet FEA, CalculiX) — both return { ok, safetyFactor, elements[{ partName, stressPa, yieldPa, safetyFactor }], failures[], diagnostics }; fea adds the threshold, the stress regions as @kc[...] faces with their location, and fea { peakStressPa, maxDisplacementMm, meshTrusted, peakAtSupportPa, refinement }; it refines the mesh automatically until the stress is trusted (refine: false for one solve).\n- 'static-hold' — gravitational holding torque/force at a sampled pose grid vs each actuated joint's declared actuator capacity ({ joint?, pose?, gravity?, min_torque_margin_pct?, range_samples? }).\n- 'motion-load' — loads on each driven joint (mechanicalJoint on a revolute mate) while the model moves: gravity, inertia from the animationView tracks (finite differences), optional external forces. Mass and inertia come from the solids and density/material, or a part's massKg. Returns per joint peak torque vs the mechanicalJoint torqueNm (margin; < 1x error, < 2x warning), axial / radial force and bending moment on the actuator shaft (checked only against radialLimitN / axialLimitN; without them 'no rating, not checked'), the radial load on each of up to two coaxial supports (each at its station on the shaft: the actuator at ","description_similarity":0.86,"before_hash":"230c5a46aadca077d240e3dda0efee68","after_hash":"d32f704f6bf6e356df42d55df80078cf"},{"tool":"evaluate_script","kind":"changed","observed_at":"2026-10-17T14:37:32.928Z","fields":["inputSchema"],"description_before":null,"description_after":null,"description_similarity":null,"before_hash":"696aab4d8112a0c723264959991dfcc9","after_hash":"04d61ad8522fc7162937f0b562714bf3"},{"tool":"write_bom","kind":"added","observed_at":"2026-10-16T14:07:45.928Z","fields":[],"description_before":null,"description_after":"Use this when you need to merge a LabWired handoff BOM with optional KernelCAD catalog parts, MPNs and pricing, then write CSV or retrieve Sheets-ready rows. Pass exactly one of handoff, handoff_json or handoff_path. This tool only writes a CSV locally; it makes no Google API calls. Returns headers, tabular rows, CSV contents and the CSV path.","description_similarity":null,"before_hash":null,"after_hash":"5b7daa4fbf507bc37c14338b787f1a7b"},{"tool":"fetch_part_model","kind":"added","observed_at":"2026-10-16T14:07:45.928Z","fields":[],"description_before":null,"description_after":"Use this when a LabWired handoff part needs a STEP or GLB model resolved from a verified HTTPS URL plus SHA-256, or from catalog_id / MPN. The tool uses fetch_part/find_part catalog plumbing, stores URL-fetched bytes in a SHA-256 cache, checks the supplied hash, compares measurable model dimensions with bbox_mm, and returns provenance or a model_not_found result. GLB bounds are checked when POSITION accessor bounds are available; otherwise bbox_check.status is not_checked.","description_similarity":null,"before_hash":null,"after_hash":"017371602e60159600dac9b1f16974f8"},{"tool":"apply_surface_blend","kind":"added","observed_at":"2026-10-16T14:07:45.928Z","fields":[],"description_before":null,"description_after":"Use this when you need to author and evaluate a fillet or chamfer on a kernelCAD Shape. Inserts Shape.fillet(radius, selector, { continuity: G1|G2 }) or Shape.chamfer(distance, selector) through the existing public API and returns the patched source plus evaluation diagnostics. Selectors accept EdgeSelector syntax, including canonical edge refs/query strings or { face: canonical name, face label, or face query }. G2 continuity applies to fillets; chamfer uses the existing chamfer API. This authors the operation and does not extract blend-surface NURBS poles; that still requires kernel surface extraction.","description_similarity":null,"before_hash":null,"after_hash":"2fa000fe6cf8588fb4fb753d0d5d4998"},{"tool":"explode_view","kind":"added","observed_at":"2026-10-16T14:07:45.928Z","fields":[],"description_before":null,"description_after":"Use this when you need an ordered exploded-view plan for an assembly. Supply parts as {name,center:[x,y,z],size:[x,y,z]} in mm, or a LabWired handoff containing parts with ref, position_mm.value and physical.bbox_mm (also accepts bbox_mm.value). Optional explicit assembly_order takes precedence over handoff assembly_order / assembly.order. Missing order falls back to input part order; parts lacking usable placement or bbox and unlisted/unknown order refs are reported. Choose mode axis (default) or radial; axis follows the requested direction, radial moves parts away from the assembly centroid. The result includes ready-to-paste param_declarations, animation_tracks and reverse_animation_tracks for animationView(), part_transforms for existing shapes, and script_fragment. cameraPlan gives framing guidance.","description_similarity":null,"before_hash":null,"after_hash":"b3a0ec4b0bcc16a6820a503e954ae110"},{"tool":"mesh_boolean","kind":"added","observed_at":"2026-10-16T14:07:45.928Z","fields":[],"description_before":null,"description_after":"Use this when the user wants to union, subtract, or intersect two imported triangle mesh solids (STL, OBJ, or 3MF). Supports union, subtract (A minus B) and intersect. Pass each operand as { file } on the MCP server or { data } with base64 mesh bytes; formats are detected or may be specified. Returns volume in mm³, triangle count and a binary STL as data_base64; pass that payload to import_step to continue modeling. Inputs must be closed, consistently oriented 2-manifold meshes. Open, non-manifold, or invalid meshes return an error. This computes mesh geometry and does not create an editable B-rep feature tree.","description_similarity":null,"before_hash":null,"after_hash":"3ba1c309093a63bfbecee7deaa32c4d4"},{"tool":"fea_summary","kind":"changed","observed_at":"2026-10-16T14:07:45.928Z","fields":["description"],"description_before":"Use this when you need a structural check's context without paying for a solve. Read-only: returns the stored summary of a previous run_fea (pass the same `output_dir`), whether the CalculiX + gmsh toolchain is available on this machine (with the install command when it is not), and the FEA material table with real E / Poisson / yield numbers so a grade is chosen against data rather than from memory. Never meshes, solves, or writes.","description_after":"Use this when you need a structural check's context without paying for a solve. Read-only: returns the stored summary of a previous run_fea (pass the same `output_dir`), whether the CalculiX + gmsh toolchain is available on this machine (with the install command when it is not; run_fea then uses its in-process voxel solver — toolchain.default_solver says which), and the FEA material table with real E / Poisson / yield numbers so a grade is chosen against data rather than from memory. Never meshes, solves, or writes.","description_similarity":0.863,"before_hash":"ceb2ef1f4ecdf7d02b0c1dbe640cbd64","after_hash":"437f65cc21ef7a41bc3cd88164cce741"},{"tool":"run_fea","kind":"changed","observed_at":"2026-10-16T14:07:45.928Z","fields":["description","inputSchema"],"description_before":"Use this when you need to know whether a part will hold a load. Runs the linear-static structural study a script declares with `shape.feaStudy({ material, fixed, loads, meshSize?, minSafetyFactor? })`: meshes the solid with quadratic tetrahedra, solves it with CalculiX, and returns evidence — peak von Mises stress (MPa), peak displacement (mm), the minimum safety factor against the material yield (taken away from the clamp-singular edges of the fixed faces; the raw clamp-edge peak is reported separately as peakAtSupportMPa), per-region hot spots named by @kc[...] face ref, mesh-quality trust flags, an equilibrium residual, and stress-heatmap PNG paths.\nRequires the external solver toolchain (CalculiX `ccx` plus the gmsh Python module). When it is absent the call fails with `fea.solver.unavailable` and the exact install command — never a silent pass.\nPass { file | code }, optional `study` (defaults to the last declared study), `output_dir` (keeps the .inp/.frd deck for reproduction), `mesh_size` (mm, overrides the study for this run), and `heatmaps: false` for a fast numbers-only run.\nMesh refinement is automatic: when the stress is untrusted only because the solver's error estimate is high, it re-solves once at 0.75x the element size (when the predicted element count fits the element budget) and returns that pass, with summary.refinement listing each pass's mesh size, element count and peak stress and why it stopped. `refine: false` solves once at mesh_size.","description_after":"Use this when you need to know whether a part will hold a load. Runs a linear-static structural study and returns evidence — peak von Mises stress (MPa), peak displacement (mm), the minimum safety factor against the material yield (taken away from the clamp-singular edges of the fixed faces; the raw clamp-edge peak is reported separately as peakAtSupportMPa), per-region hot spots named by @kc[...] face ref, mesh trust flags, an equilibrium residual, and (CalculiX only) stress-heatmap PNG paths.\nThe study is EITHER declared in the script with `shape.feaStudy({ material, fixed, loads, meshSize?, minSafetyFactor? })` OR passed on the call against the shape the script returns: { code: 'return box(100, 20, 10);', material: 'aluminum-6061', fixed: { atX: 0 }, loads: [{ faces: { atX: 100 }, force: [0, 0, -200] }] }. Faces are a FaceQuery ({ atX | atY | atZ, byNormal: 'Z', near: [x,y,z], ... }), a face label ('top', 'bottom', 'left', 'right', 'front', 'back'; it must name ONE face — after a boolean 'top' can be several, which is an error listing them) or an @kc[...] ref. Force is the TOTAL [Fx, Fy, Fz] in N on those faces (a scalar force + direction is accepted). Materials: mild-steel, aluminum-6061, pla, petg, abs, nylon (aliases steel, aluminum), or { E, nu, yield } in MPa.\nSolver (`solver`, default 'auto'): CalculiX + gmsh quadratic tets when that toolchain is installed; otherwise the built-in in-process voxel solver (8-node incompatible-mode bricks), which needs nothing installed and is marked summary.solver 'in-process-voxel' with trust.meshTrusted false — an estimate (accurate for prismatic bending, approximate at curved faces and notches), never a verified pass. solver: 'calculix' fails up front with fea.solver.unavailable and the install command when the toolchain is absent.\nAlso: `study` (a declared study name; default the last), `output_dir` (keeps the deck / summary JSON), `mesh_size` (mm, overrides the study for this run), `heatmaps: false` for a numbers-only run. CalculiX mesh refinement is automatic: when the stress is untrusted only because the solver's error estimate is high, it re-solves once at 0.75x the element size (inside the element budget), with summary.refinement listing each pass. `refine: false` solves once.","description_similarity":0.529,"before_hash":"77a9a9991207bcaecbc0924ecbbae6a8","after_hash":"754e59fcf7b30b7753befe53eb13c15b"},{"tool":"flatten_pattern","kind":"changed","observed_at":"2026-10-16T14:07:45.928Z","fields":["description"],"description_before":"Use this when you need the unfolded flat pattern of a bent sheet-metal part. Return the unfolded 2D flat-pattern of a bent sheet-metal Shape as a Region (outer polyline + holes + bend lines + sketch plane). Slice 1: at most 2 bends. Pass { file } or { code }; optional { featureId } to pick a specific Shape.","description_after":"Use this when you need the unfolded flat pattern of a bent sheet-metal part. Return the unfolded 2D flat-pattern of a bent sheet-metal Shape as a Region (outer polyline + holes + bend lines + sketch plane). Any number of parallel bends; crossing bends need corner relief. Pass { file } or { code }; optional { featureId } to pick a specific Shape.","description_similarity":0.771,"before_hash":"df363e4be7a065f5d26c56c07c8826b5","after_hash":"4c372d7b96e647bcd445219d5e8c469d"},{"tool":"lookup_cookbook","kind":"changed","observed_at":"2026-10-16T14:07:45.928Z","fields":["inputSchema"],"description_before":null,"description_after":null,"description_similarity":null,"before_hash":"cca7c1e1bbf696445a140c355aeb294c","after_hash":"d8edca1b1668cc63e699cc315a7941db"},{"tool":"query","kind":"changed","observed_at":"2026-10-16T14:07:45.928Z","fields":["description","inputSchema"],"description_before":"Use this when you need to resolve or inspect topology against a script's lowered geometry. Selected by `mode` (default 'evaluate'):\n- 'evaluate' — inspect a Query (@kc[...] ref, @kcq[...] DSL, or { ast }); returns matched entities. Pass expect:'unique' to assert exactly-one.\n- 'resolve' — resolve a single @kc[...] / @kcq[...] ref to one entity ({ ref }).\n- 'lineage' — walk the HistoryMap for a named face ref ({ feature_id, ref }).\nAll params except `mode` are forwarded verbatim.","description_after":"Use this when you need to resolve or inspect topology against a script's lowered geometry. Pass the script as `code` (inline; works on a hosted server) or `file`. Selected by `mode` (default 'evaluate'):\n- 'evaluate' — list the faces a Query matches ({ query }). Pass expect:'unique' to assert exactly-one.\n- 'resolve' — resolve one ref to one face ({ ref }).\n- 'lineage' — the creating/modifying history of a face ({ ref }; feature_id defaults to the last feature).\nQuery forms (faces only; edge/vertex kinds return query.unsupported-entity-type):\n- a bare face label: 'top', 'bottom', 'left', 'right', 'front', 'back', or a hole/cutout slot like 'wall'.\n- @kc[<feature-id>/face/<label>] — feature ids are the ones refs print, e.g. '@kc[box_1/face/top]', '@kc[hole_1/face/wall]'.\n- @kcq[face(<filter>, ...)] — filters AND together: createdBy(\"box_1\"), withLabel(\"top\"), geometryType(PLANE|CYLINDER|CONE|SPHERE|TORUS|BSPLINE_SURFACE), closestTo([x,y,z]) or closestTo([x,y,z], k), containsPoint([x,y,z]); combine with union(a, b), intersection(a, b), subtraction(a, b). Example: '@kcq[face(geometryType(CYLINDER), closestTo([0,0,10]))]'.\nEach matched face comes back with its canonical @kc ref, centroid, normal and area.","description_similarity":0.289,"before_hash":"bc703315d183aad6dd5a52b6da37aff2","after_hash":"31fcaa46208a9d984811fb56d5a072ec"},{"tool":"add_variable_sweep","kind":"changed","observed_at":"2026-10-16T14:07:45.928Z","fields":["description","inputSchema"],"description_before":"Use this when you need an organic swept solid whose cross-section changes along its length — a tapering body, horn, bottle, fairing, or duct — authored as a variable-section sweep along a spine. Insert a `variableSweep(spine, sections, opts?)` declaration into the user's .kcad.ts immediately before the last top-level return. The result is a Shape — chain `.translate(...)`, `.union(...)`, etc. via `add_feature`. `spine_binding` references an existing variable (Curve3D / Sketch / Vec3[]) in the source; each `sections[i].profile_binding` references an existing Sketch. Sections must be strictly increasing in `t` and span [0, 1]; first t=0, last t=1. Orientation is not exposed by this MCP tool until runtime orientation support is wired. Validates every binding exists in the source via regex before inserting (fast structured error vs capture-time stack). Returns the modified code + diagnostics. Side-effect-free.","description_after":"Use this when you need an organic swept solid whose cross-section changes along its length — a tapering body, horn, bottle, handle, ring band, fairing, or duct — authored as a variable-section sweep along a spine. Inserts `variableSweep(spine, sections, opts?)` into the .kcad.ts `code` immediately before the last top-level return (an empty `code` starts a new script that returns the sweep). Spine: EITHER `spine_points` ([[x,y,z], ...] in mm, interpolated with spline3d; `spine_closed: true` closes the loop for a ring) OR `spine_binding` (an existing Curve3D / Sketch / Vec3[] variable). Each section: `t` in [0, 1] plus a profile — inline `radius` (circle) or `width` + `height` (rectangle), or `profile_binding` (an existing Sketch); profiles are centred on the spine and turned to face along it. Sections are strictly increasing in t, first t=0, last t=1 (omit t on every section to space them evenly). On a closed spine t=1 is the seam and reuses the t=0 profile. Example: { code, spine_points: [[0,0,0],[0,10,30],[0,0,60]], sections: [{ t: 0, radius: 8 }, { t: 0.5, radius: 10 }, { t: 1, radius: 4 }] }. Returns the modified code, diagnostics from re-evaluating it, and `sweep` { volumeMm3, bbox } measured from the built solid (ok:false when the sweep built nothing). The result is a Shape binding: return it, or chain `.union(...)` etc. via add_feature. Orientation is not exposed by this MCP tool until runtime orientation support is wired. Side-effect-free.","description_similarity":0.503,"before_hash":"15aaeb68ecba8a42152a2480370a61dd","after_hash":"43990ccfe2b8bafc73caa98e8c8ca469"},{"tool":"verify","kind":"changed","observed_at":"2026-10-16T14:07:45.928Z","fields":["description","inputSchema"],"description_before":"Use this when you need to check a design against a rule set. One verifier, selected by `check`:\n- 'assembly' — mate-aware assembly validator on the active session (run evaluate_script first).\n- 'urdf' — structural validity of a .urdf file ({ urdf_path }).\n- 'dfm' — print-readiness gates declared by dfmSpec() ({ file | code }).\n- 'dfm-preflight' — sheet-metal flat pattern vs a job-shop's ordering rules ({ vendor, material, thicknessIn|thicknessMm, ... }). Returns the vendor's catalog source pages as `sources`; when `disclosure` is present, show it with those links.\n- 'assembly-path' — continuous straight-line removal of each assembly part along ±X/±Y/±Z and optional world-space directions. Returns valid directions and blocking parts; disassemblyOrder runs a deterministic greedy removal pass. Watertight mesh approximation, conservative contact, no rotation/mate/hardware certification.\n- 'swept-collision' — sweep declared joint range(s) and report colliding poses.\n- 'reachable' — inverse-kinematics reachability for an end-effector ({ tip_link, target_position, ... }).\n- 'geometry-quality' — one solid body's BREP tiny faces and short edges (ids, locations, mm²/mm), plus sampled mirror symmetry about centroid XY/YZ/XZ and principal inertia planes ({ file | code, feature_id?, tiny_face_area_mm2?, tiny_face_relative?, short_edge_length_mm?, symmetry_tolerance_mm?, mesh_deflection_mm?, asserted_plane?: { origin, normal } }). Relative area is a fraction of total surface area; thresholds are ORed. Candidate planes are discovery; only an asserted plane gates symmetry. Approximate sampled tessellation, not exact BREP proof.\n- 'fastener-installation' — measured explicit catalog-screw installation stations on lowered assembly BREP ({ file | code, fasteners:[{ part, against, engagementPart?, minEngagementMm?, maxProtrusionMm? }], toleranceMm?, angleToleranceDeg? }). Reports annular bearing gap, bore axis/diameter/overlap and receiver geometric engagement/protrusion. Unknown or zero coverage cannot pass. Simplified threads do not certify torque, preload or strength.\n- 'mounting-holes' — fastened mates expose matching hole diameters on both sides.\n- 'load-capacity' — will it hold? Closed-form Euler-Bernoulli beam check ({ loads, materials, ... }), or mode:'fea' to solve the script's feaStudy (quadratic-tet FEA, CalculiX) — both return { ok, safetyFactor, elements[{ partName, stressPa, yieldPa, safetyFactor }], failures[], diagnostics }; fea adds the threshold, the stress regions as @kc[...] faces with their location, and fea { peakStressPa, maxDisplacementMm, meshTrusted, peakAtSupportPa, refinement }; it refines the mesh automatically until the stress is trusted (refine: false for one solve).\n- 'static-hold' — gravitational holding torque/force at a sampled pose grid vs each actuated joint's declared actuator capacity ({ joint?, pose?, gravity?, min_torque_margin_pct?, range_samples? }).\n- 'body-likeness' — publish gate for organic/car bodies: cheap AABB↔wheel checks plus required agent still verdicts (side-body-over-wheels, side-cabin-aft, rear-haunch, ortho-proportions-vs-reference). Pass { body_bbox | code/file+body_feature_id, wheels?, cabin_bbox?, still_verdicts?, require_stills? }. Full CV silhouette matching is NOT implemented — agents must inspect ortho PNGs/Studio and supply still_verdicts before claiming success.\n- 'edge-radius' — general edge-break specification on final BREP ({ file | code, min_radius_mm?, max_radius_mm?, require_edge_break?: 'external'|'internal'|'all', feature_id?, assembly?, parts?, edges?, faces? }). Reports sharp convex/concave edges, analytic cylindrical/toroidal fillet radii and spherical junctions, and heuristic planar chamfer strips. Radius bounds apply only to fillets; selectors/points are part-local. Unknown/empty coverage cannot pass.\nAll params except `check` are check-specific and forwarded verbatim; each check fails closed on its own missing required params.","description_after":"Use this when you need to check a design against a rule set. One verifier, selected by `check`:\n- 'assembly' — static assembly review ({ file | code }, or the session evaluate_script left): mate validator, default-pose interference, joint topology, mechanical plausibility. ok:false with `blocking[]` exactly when review_cad's blocking rules fire on these findings; review_cad also sweeps joint ranges and runs physics.\n- 'urdf' — structural validity of a .urdf file ({ urdf_path }).\n- 'dfm' — print-readiness gates declared by dfmSpec() ({ file | code }).\n- 'dfm-preflight' — sheet-metal flat pattern vs a job-shop's ordering rules ({ vendor, material, thicknessIn|thicknessMm, ... }). Returns the vendor's catalog source pages as `sources`; when `disclosure` is present, show it with those links.\n- 'assembly-path' — continuous straight-line removal of each assembly part along ±X/±Y/±Z and optional world-space directions. Returns valid directions and blocking parts; disassemblyOrder runs a deterministic greedy removal pass. Watertight mesh approximation, conservative contact, no rotation/mate/hardware certification.\n- 'swept-collision' — sweep declared joint range(s) and report colliding poses.\n- 'reachable' — inverse-kinematics reachability for an end-effector ({ tip_link, target_position, ... }).\n- 'geometry-quality' — one solid body's BREP tiny faces and short edges (ids, locations, mm²/mm), plus sampled mirror symmetry about centroid XY/YZ/XZ and principal inertia planes ({ file | code, feature_id?, tiny_face_area_mm2?, tiny_face_relative?, short_edge_length_mm?, symmetry_tolerance_mm?, mesh_deflection_mm?, asserted_plane?: { origin, normal } }). Relative area is a fraction of total surface area; thresholds are ORed. Candidate planes are discovery; only an asserted plane gates symmetry. Approximate sampled tessellation, not exact BREP proof.\n- 'fastener-installation' — measured explicit catalog-screw installation stations on lowered assembly BREP ({ file | code, fasteners:[{ part, against, engagementPart?, minEngagementMm?, maxProtrusionMm? }], toleranceMm?, angleToleranceDeg? }). Reports annular bearing gap, bore axis/diameter/overlap and receiver geometric engagement/protrusion. Unknown or zero coverage cannot pass. Simplified threads do not certify torque, preload or strength.\n- 'mounting-holes' — fastened mates: hole pairs one screw can use (equal, or clearance over a tap drill / hole({ thread }) of the same metric size; hole-free faces are a rigid bond) and fastener holes meeting at the contact face are coaxial. Sides it cannot resolve are info, never mismatches.\n- 'load-capacity' — will it hold? Closed-form Euler-Bernoulli beam check ({ loads, materials, ... }), or mode:'fea' to solve the script's feaStudy (quadratic-tet FEA, CalculiX) — both return { ok, safetyFactor, elements[{ partName, stressPa, yieldPa, safetyFactor }], failures[], diagnostics }; fea adds the threshold, the stress regions as @kc[...] faces with their location, and fea { peakStressPa, maxDisplacementMm, meshTrusted, peakAtSupportPa, refinement }; it refines the mesh automatically until the stress is trusted (refine: false for one solve).\n- 'static-hold' — gravitational holding torque/force at a sampled pose grid vs each actuated joint's declared actuator capacity ({ joint?, pose?, gravity?, min_torque_margin_pct?, range_samples? }).\n- 'body-likeness' — publish gate for organic/car bodies: cheap AABB↔wheel checks plus required agent still verdicts (side-body-over-wheels, side-cabin-aft, rear-haunch, ortho-proportions-vs-reference). Pass { body_bbox | code/file+body_feature_id, wheels?, cabin_bbox?, still_verdicts?, require_stills? }. Full CV silhouette matching is NOT implemented — agents must inspect ortho PNGs/Studio and supply still_verdicts before claiming success.\n- 'edge-radius' — general edge-break specification on final BREP ({ file | code, min_radius_mm?, max_radius_mm?, require_edge_break?: 'external'|'internal'|'all', feature_id?, assembly?, part","description_similarity":0.896,"before_hash":"490ae4c62c0d185eb0ef302888d1266e","after_hash":"230c5a46aadca077d240e3dda0efee68"},{"tool":"diff_scripts","kind":"changed","observed_at":"2026-10-16T14:07:45.928Z","fields":["description","inputSchema"],"description_before":"Use this when you need to see exactly what changed between two script versions. Structured geometric delta between two versions of a kernelCAD script — a baseline ({ baseFile } or { baseCode }) and a revision ({ file } or { code }). Returns agent-readable JSON: per-part added/removed/renamed/changed (volume mm³ + exact bbox deltas, numbers matching inspect({ of: 'part-stats' })), total interference-volume delta with per-pair detail, mate-graph changes (added/removed/changed mates incl. type, connectors, pose, limits), and param changes (value/min/max). Single-shape scripts diff as one \"(root)\" pseudo-part. Use after editing a script to verify exactly what changed physically before re-rendering. Read-only — never touches the active session.","description_after":"Use this when you need to see exactly what changed between two script versions. Structured geometric delta between two versions of a kernelCAD script — a baseline ({ baseFile } or { baseCode }) and a revision ({ file } or { code }). Returns agent-readable JSON: per-part added/removed/renamed/changed (volume mm³ + exact bbox deltas, numbers matching inspect({ of: 'part-stats' })), total interference-volume delta with per-pair detail, mate-graph changes (added/removed/changed mates incl. type, connectors, pose, limits), and param changes (value/min/max). Single-shape scripts diff as one \"(root)\" pseudo-part; a `return [a, b]` multi-body script diffs per body as \"body[0]\", \"body[1]\". An error that still leaves geometry (e.g. a skipped fillet) is listed under base/revised.errors beside the diff. Use after editing a script to verify exactly what changed physically before re-rendering. On a hosted server pass both versions inline: { baseCode: 'return box(10, 10, 10);', code: 'return box(10, 10, 12);' } (base_code/old_code/before and revised_code/new_code/after are accepted as aliases). Read-only — never touches the active session.","description_similarity":0.694,"before_hash":"4c40a8636565195ede5d9f7b1c7c7c1d","after_hash":"1127328e87444fddf6a0e9f8d3059218"},{"tool":"evaluate_script","kind":"changed","observed_at":"2026-10-16T14:07:45.928Z","fields":["description"],"description_before":"Use this when you need to run a script and check it compiles. Full local builds return viewerUrl: a live Studio link reused and updated on later full builds in the same MCP process. Hosted builds return viewerMode: hosted and viewerHint pointing to open_in_studio; they do not start a loopback viewer. Full evaluations return step evidence: build validity, volume and before/after local PNG paths in one shared iso frame. Snapshots require PW_CDP_URL for an existing browser; unavailable captures report an explicit error. Run a kernelCAD .kcad.ts script and report pass/fail + feature count + diagnostics + sceneSummary (BREP validity, volume in mm³, face count, bounding size in mm). When the scene is assembly-built (assembly().part(...) → .model()/.solvedModel()), also returns a parts summary { count, names } AND runs the mechanism-truth gate by default: the `mechanism` field reports real/broken/unverified and a broken mechanism (disconnected components / mechanism.orphan-part, self-collision, fastened drift, dof-mismatch) makes ok:false with the failures in diagnostics — a mechanism (any mate, joint, transmission or .solvedModel()) needs every part linked by connectors + mates/joints (axis+revolute for shafts/hinges/gears; frame+fastened for rigid; or arm.revolute/.prismatic/.ball/.fixed). A plain multi-part assembly with no mates (base + lid, print layout) is independent bodies and passes. Pass { skipMechanismCheck: true } to opt out (e.g. a deliberately free part next to a mechanism). An animation or drive on a fastened joint (mechanism.motion-on-fixed-joint) is broken: animate a revolute/prismatic mate pose. For a model with moving joints or motion intent, `mechanismSummary.statement` is one plain line: \"Motion checked: ...\" names what ran; \"Motion not checked: ...\" is NOT a pass — never call that mechanism working. Every union() is checked too (no opt-out): union.disconnected (the union is several separate solids — a floating operand) and union.member-overlap (two operands that each carry their own .finish()/.material(), the same one, share > 1 mm³ — cut members to fit, e.g. a cross tube between rails is span minus two rail widths) make ok:false. Pass either { file: \"<path>\" } or { code: \"<inline source>\" }. Set { dryRun: true } for fast validation while iterating: transpile + capture + capture-light checks without building solids, DFM gates, or meshing — milliseconds instead of seconds (100x+ on boolean/fillet-heavy scripts). A dry run catches script throws, capture-time API misuse, and assembly validity-gate failures, but NOT lowering failures or dfmSpec diagnostics; it leaves the active session untouched, so finish with a full (non-dry) evaluate_script before using session-dependent tools. To show a measurement in the 3D viewer (e.g. hole spacing), declare it in the script with shape.dimension({ kind: \"linear\", from, to, label }); a full evaluate lists them as dimensions: [{ text, kind, source }], and a shared /p link with ?dims=1 forces them on. Hosted: lib.fromSTEP / fromSTL / fromDXF / fromSVG and referenceImage take a direct string literal or a const bound to one (computed expressions are unsupported). They accept \"asset:<id>\" (from request_upload), an https:// URL or a data: URI as the path.","description_after":"Use this when you need to run a script and check it compiles. Full local builds return viewerUrl: a live Studio link reused and updated on later full builds in the same MCP process. Hosted builds return viewerMode: hosted and viewerHint pointing to open_in_studio; they do not start a loopback viewer. Full evaluations return step evidence: build validity, volume and before/after local PNG paths in one shared iso frame. Snapshots require PW_CDP_URL for an existing browser; unavailable captures report an explicit error. Run a kernelCAD .kcad.ts script and report pass/fail + feature count + diagnostics + sceneSummary (BREP validity, volume in mm³, face count, bounding size in mm). When the scene is assembly-built (assembly().part(...) → .model()/.solvedModel()), also returns a parts summary { count, names } AND runs the mechanism-truth gate by default: the `mechanism` field reports real/broken/unverified and a broken mechanism (disconnected components / mechanism.orphan-part, self-collision, fastened drift, dof-mismatch) makes ok:false with the failures in diagnostics — a mechanism (any mate or joint) needs every part linked by connectors + mates/joints (axis+revolute for shafts/hinges/gears; frame+fastened for rigid; or arm.revolute/.prismatic/.ball/.fixed). A plain multi-part assembly with no mates (base + lid, print layout) is independent bodies and passes. Pass { skipMechanismCheck: true } to opt out (e.g. a deliberately free part next to a mechanism). An animation or drive on a fastened joint (mechanism.motion-on-fixed-joint) is broken: animate a revolute/prismatic mate pose. For a model with moving joints or motion intent, `mechanismSummary.statement` is one plain line: \"Motion checked: ...\" names what ran; \"Motion not checked: ...\" is NOT a pass — never call that mechanism working. Every union() is checked too (no opt-out): union.disconnected (the union is several separate solids — a floating operand) and union.member-overlap (two operands that each carry their own .finish()/.material(), the same one, share > 1 mm³ — cut members to fit, e.g. a cross tube between rails is span minus two rail widths) make ok:false. Pass either { file: \"<path>\" } or { code: \"<inline source>\" }. Set { dryRun: true } for fast validation while iterating: transpile + capture + capture-light checks without building solids, DFM gates, or meshing — milliseconds instead of seconds (100x+ on boolean/fillet-heavy scripts). A dry run catches script throws, capture-time API misuse, and assembly validity-gate failures, but NOT lowering failures or dfmSpec diagnostics; it leaves the active session untouched, so finish with a full (non-dry) evaluate_script before using session-dependent tools. To show a measurement in the 3D viewer (e.g. hole spacing), declare it in the script with shape.dimension({ kind: \"linear\", from, to, label }); a full evaluate lists them as dimensions: [{ text, kind, source }], and a shared /p link with ?dims=1 forces them on. Hosted: lib.fromSTEP / fromSTL / fromDXF / fromSVG and referenceImage take a direct string literal or a const bound to one (computed expressions are unsupported). They accept \"asset:<id>\" (from request_upload), an https:// URL or a data: URI as the path.","description_similarity":0.997,"before_hash":"0bb4e15e665aa4fc2b155909b35fe1b0","after_hash":"696aab4d8112a0c723264959991dfcc9"},{"tool":"lookup_authoring_skill","kind":"changed","observed_at":"2026-10-16T14:07:45.928Z","fields":["description","inputSchema"],"description_before":"Return the kernelcad-authoring skill — conventions for writing .kcad.ts scripts (API surface, parameters, evaluation contract, common pitfalls) — in sections.\n\nCall with NO arguments first: you get the quick-start (units, axes, the return rule, conventions) and an index of every section with a one-line summary (under ~8k chars). Then pull what you need: `{ section: \"<id>\" }` returns one section (e.g. \"top-level-functions\", \"materials\", \"dfm-gates-print-readiness\"); `{ query: \"fillet after subtract\" }` returns the best-matching sections. `{ section: \"all\" }` returns the full ~108k-char SKILL.md — only if your client accepts large responses.\n\nClients that list resources can also read `kernelcad://skills/authoring` (the full body).\n\nOUTPUT: { uri, mimeType, mode, text, sections? } — `mode` is index | section | search | all | not-found.","description_after":"Return the kernelcad-authoring skill — conventions for writing .kcad.ts scripts (API surface, parameters, evaluation contract, common pitfalls) — in sections.\n\nCall with NO arguments first: you get the quick-start (units, axes, the return rule, the rules that prevent most failures, the intent → API routing table, the \"Before you finish\" checklist) and an index of every section with a one-line summary (under 16k chars). Then pull what you need: `{ section: \"<id>\" }` returns one section (e.g. \"top-level-functions\", \"materials\", \"dfm-gates-print-readiness\"); `{ query: \"fillet after subtract\" }` returns the best-matching sections. `{ section: \"all\" }` returns the full ~140k-char skill (SKILL.md plus its reference files) — only if your client accepts large responses.\n\nClients that list resources can also read `kernelcad://skills/authoring` (the SKILL.md core).\n\nOUTPUT: { uri, mimeType, mode, text, sections? } — `mode` is index | section | search | all | not-found.","description_similarity":0.825,"before_hash":"bd212cd3f15193b4a2d087ea409c33a7","after_hash":"e28a2a3d296b634e4ab1d282fd40134c"},{"tool":"import_handoff","kind":"added","observed_at":"2026-10-16T03:11:57.227Z","fields":[],"description_before":null,"description_after":"Use this when you need to place parts from a LabWired handoff.json into a KernelCAD assembly. Pass the parsed handoff object using schema labwired-kernelcad-handoff/0.1. The tool validates the handoff and returns an evaluable assembly script with corner-anchored bbox placeholder solids, origin/bbox-face/mounting-hole/pin anchors, endpoint connectivity mates for wires whose two endpoint positions are known, and structured cutout_hints from connector faces. These mates express connectivity intent only; no wire geometry or routing is generated. It does not cut enclosure walls or fetch STEP/GLB assets. position_mm locates the bbox lower corner; bbox.center is derived. Null, estimated, proposed, and other non-exact geometry is reported as warnings and omitted or placed at zero as appropriate.","description_similarity":null,"before_hash":null,"after_hash":"5a64bb315c7290e644d5945cae0b1827"},{"tool":"route_wires","kind":"added","observed_at":"2026-10-16T03:11:57.227Z","fields":[],"description_before":null,"description_after":"Use this when you need a first-pass orthogonal pin-to-pin wire route estimate and clearance check. Accepts a LabWired handoff or explicit wire positions in millimetres, returns path length and bend count, and reports collisions against part bounding boxes. Wires whose endpoint positions are null are reported as unresolved. Read-only analysis; it does not create or certify a physical harness.","description_similarity":null,"before_hash":null,"after_hash":"706cd5585e453297a14654a22bd21818"},{"tool":"fit_plane","kind":"added","observed_at":"2026-10-16T03:11:57.227Z","fields":[],"description_before":null,"description_after":"Use this when you need to fit an orthogonal least-squares plane to XYZ point-cloud data. Returns centroid, deterministic unit normal, signed point residuals, RMS residual and maximum absolute residual. Accepts points already parsed by the caller from scan data or mesh vertices. Computes parameters only; it does not create a surface body. Requires at least three non-collinear finite points.","description_similarity":null,"before_hash":null,"after_hash":"763e017b6f138de43c82d8d0a7352749"},{"tool":"inspect_nurbs","kind":"added","observed_at":"2026-10-16T03:11:57.227Z","fields":[],"description_before":null,"description_after":"Use this when you need the captured NURBS definition for a kernelCAD nurbsCurve/spline3d feature. Returns degree, distinct knots and multiplicities, poles, weights, rational and uniformWeights flags, hasNonUnitWeights, and parameter range. Defaults to the last captured curve; pass feature_id to choose one. Reports authored data, not exact geometry-derived B-rep edge/face NURBS. Surface extraction and blending are not supported.","description_similarity":null,"before_hash":null,"after_hash":"b121809650a7ee9bc4b036844c36490a"},{"tool":"ray_pick","kind":"added","observed_at":"2026-10-16T03:11:57.227Z","fields":[],"description_before":null,"description_after":"Use this when you need the faces a ray hits in a local Studio model, nearest first, with points, distances, and normals. Inputs are model units (mm); direction is normalized. Requires the local Studio URL and session token for the same script, reads the current model generation, and returns a set_selection argument object with every hit. feature_id must identify a displayed terminal shape; intermediates have no current viewer shapeIndex. Intersections use the viewer per-face tessellation, so curved-surface points and normals are mesh approximations.","description_similarity":null,"before_hash":null,"after_hash":"2018091c94be1e03ff82a761db6d39ab"},{"tool":"set_selection","kind":"changed","observed_at":"2026-10-16T03:11:57.227Z","fields":["description"],"description_before":"Use this when you need to replace the shared local Studio face/edge selection, or clear it with selection:null. The viewer highlights the pick on its next sync (300 ms). Does not edit geometry. Pass model_generation from get_selection. Use indices from the current viewer mesh/get_selection; they expire on rebuild. Requires a local Studio session.","description_after":"Use this when you need to replace the shared local Studio face/edge selection, or clear it with selection:null. The viewer highlights the pick on its next sync (300 ms). Does not edit geometry. Pass model_generation from get_selection; writes from an older generation are rejected. Use only current shape indices. Requires a local Studio session.","description_similarity":0.792,"before_hash":"506fcec7a6485fc521f464551402a8e5","after_hash":"46d99e8a179734aba770f231addefca9"},{"tool":"get_selection","kind":"changed","observed_at":"2026-10-16T03:11:57.227Z","fields":["description"],"description_before":"Use this when you need to read the human/agent selection in a local Studio session. Returns one clicked face or edge (or null), with mesh-local shapeIndex/kind/id and creating featureId. Use for “this edge”; indices expire on rebuild. featureId is provenance, not the owner of a stable topology ref. Inspect the current shape before authoring a fillet. Requires a running local Studio opened on the same script; hosted sessions are not supported.","description_after":"Use this when you need to read the human/agent selection in a local Studio session. Returns one clicked face or edge (or null), with current-generation mesh-local shapeIndex/kind/id and creating featureId. During a rebuild selection is null with “selection pending rebuild” until Studio uniquely verifies the face; ambiguous or deleted faces are cleared. Inspect the current shape before authoring a fillet. Requires a running local Studio opened on the same script; hosted sessions are not supported.","description_similarity":0.725,"before_hash":"9b984288f1654750be6a170a94bc0e69","after_hash":"60c88fcbd837ce73146c1408b4920ae8"},{"tool":"export","kind":"changed","observed_at":"2026-10-16T03:11:57.227Z","fields":["description","inputSchema"],"description_before":"Use this when you need to export geometry to a file. One exporter, selected by `target`:\n- target:'model' — export the script geometry to one file. Pass { file | code }, a required { output_path }, and { format }. Supported formats: stl (binary STL mesh), step (BREP CAD interchange), dxf (2D cut file for laser / waterjet / CNC: a flat part — plate, panel, extruded profile, in any orientation — exports its outline and holes in its own plane with exact arcs and circles; a sheet-metal part or a returned Region exports its flat pattern; a flat or sheet-metal part also returns sheet { thickness_mm, bend_count }, which a shop needs and the DXF does not carry; options.section { axis: \"x\"|\"y\"|\"z\", at } exports the cross-section of any part in world coordinates (plans, profiles); a multi-part model (cut list) writes all parts side by side on output_path, one layer per part, plus parts/<part>.dxf per part (reported in part_files; options.layout 'sheet' writes the combined sheet only); any other part fails with export.dxf.non-planar), 3mf (slicer-friendly mesh: one named object per part, colours as core-spec basematerials named by the part's engineering material; options.arrange 'plate' packs parts on the bed at Z=0 without overlap (options.orient puts each part's largest flat face down), 'assembled' keeps them together as one multi-part object for multi-colour prints; options.slicer 'bambu' | 'orca' | 'prusa' adds that slicer's per-object name + filament-slot sidecar — slot N is the Nth distinct colour/material), options.infill { fromFea: '<study>' | true, bands?, pattern? } = stress-graded FDM infill (requires the local CalculiX + gmsh toolchain; without it the export fails with fea.solver.unavailable): solves the feaStudy and writes modifier volumes, each with its own infill density (Orca/Bambu format by default; options.slicer 'prusa' writes PrusaSlicer's format instead, since the two are not interchangeable); the result carries infill { bands, saving, images }), gcode (installed OrcaSlicer output; preserves G-code and returns optional gcode_stats with header generator identity and slicer-predicted time/material), glb (web-viewer / AR with PBR materials), svg-drawing (third-angle engineering-drawing sheet: front/top/left + isometric views, hidden edges dashed, tangent edges thin, overall bounding-box dimensions, title block; assemblies are drawn with inter-part occlusion; pass options.annotations to dimension specific features instead of the bounding box; pass options.exploded { factor, mode } to explode the isometric cell, options.balloons to number parts from the BOM, and options.partsList for an item/name/qty/material table above the title block). overall bounding-box dimensions, title block; assemblies are drawn with inter-part occlusion; pass options.annotations to dimension specific features instead of the bounding box, options.autoAnnotate to derive datums A/B/C, grouped hole callouts with position tolerances, hole positions, overall size, radius and chamfer callouts, flatness and an ISO 2768 note from the geometry (the result carries drawing_report with placed / overlapped counts), and options.sections for real section views on any cutting plane). pdf-drawing (the same sheet — views, dashed hidden lines, dimensions, hole callouts, GD&T, sections, parts list — as a printable vector PDF on a standard sheet, one call: ISO a4|a3|a2|a1|a0 or ANSI ansi-a…ansi-e landscape, default a3, or sheet \"auto\" / \"auto-ansi\" for the smallest sheet that holds the views at 1:1; the drawing scale is picked to fit; projection \"third\" (default) or \"first\" arranges the views and draws the matching symbol; a full title block carries title, part name, material, scale, units, sheet size, date and revision, settable through options.title / partName / material / revision / date; autoAnnotate is on unless options.annotations is given). Robot descriptions: urdf (tree-topology robot description), srdf (motion-planning semantics layered over the URDF), sdf-g","description_after":"Use this when you need to export geometry to a file. One exporter, selected by `target`:\n- target:'model' — export the script geometry to one file. Pass { file | code }, a required { output_path }, and { format }. Supported formats: stl (binary STL mesh), step (BREP CAD interchange), dxf (2D cut file for laser / waterjet / CNC: a flat part — plate, panel, extruded profile, in any orientation — exports its outline and holes in its own plane with exact arcs and circles; a sheet-metal part or a returned Region exports its flat pattern; a flat or sheet-metal part also returns sheet { thickness_mm, bend_count }, which a shop needs and the DXF does not carry; options.section { axis: \"x\"|\"y\"|\"z\", at } exports the cross-section of any part in world coordinates (plans, profiles); a multi-part model (cut list) writes all parts side by side on output_path, one layer per part, plus parts/<part>.dxf per part (reported in part_files; options.layout 'sheet' writes the combined sheet only); any other part fails with export.dxf.non-planar), 3mf (slicer-friendly mesh: one named object per part, colours as core-spec basematerials named by the part's engineering material; options.arrange 'plate' packs parts on the bed at Z=0 without overlap (options.orient puts each part's largest flat face down), 'assembled' keeps them together as one multi-part object for multi-colour prints; options.slicer 'bambu' | 'orca' | 'prusa' adds that slicer's per-object name + filament-slot sidecar — slot N is the Nth distinct colour/material), options.infill { fromFea: '<study>' | true, bands?, pattern? } = stress-graded FDM infill (requires the local CalculiX + gmsh toolchain; without it the export fails with fea.solver.unavailable): solves the feaStudy and writes modifier volumes, each with its own infill density (Orca/Bambu format by default; options.slicer 'prusa' writes PrusaSlicer's format instead, since the two are not interchangeable); the result carries infill { bands, saving, images }), gcode (installed OrcaSlicer output; preserves G-code and returns optional gcode_stats with header generator identity and slicer-predicted time/material), glb (web-viewer / AR with PBR materials), obj (Wavefront indexed triangle mesh), usd (ASCII USDA triangle mesh in millimeter, Z-up coordinates; multi-part scenes emit one named mesh per part), svg-drawing (third-angle engineering-drawing sheet: front/top/left + isometric views, hidden edges dashed, tangent edges thin, overall bounding-box dimensions, title block; assemblies are drawn with inter-part occlusion; pass options.annotations to dimension specific features instead of the bounding box; pass options.exploded { factor, mode } to explode the isometric cell, options.balloons to number parts from the BOM, and options.partsList for an item/name/qty/material table above the title block). overall bounding-box dimensions, title block; assemblies are drawn with inter-part occlusion; pass options.annotations to dimension specific features instead of the bounding box, options.autoAnnotate to derive datums A/B/C, grouped hole callouts with position tolerances, hole positions, overall size, radius and chamfer callouts, flatness and an ISO 2768 note from the geometry (the result carries drawing_report with placed / overlapped counts), and options.sections for real section views on any cutting plane). pdf-drawing (the same sheet — views, dashed hidden lines, dimensions, hole callouts, GD&T, sections, parts list — as a printable vector PDF on a standard sheet, one call: ISO a4|a3|a2|a1|a0 or ANSI ansi-a…ansi-e landscape, default a3, or sheet \"auto\" / \"auto-ansi\" for the smallest sheet that holds the views at 1:1; the drawing scale is picked to fit; projection \"third\" (default) or \"first\" arranges the views and draws the matching symbol; a full title block carries title, part name, material, scale, units, sheet size, date and revision, settable through options.title / partName / material / revision / date; autoAnnotate is on unless o","description_similarity":0.987,"before_hash":"20b6cb2151677a083bd1fe7d7599ce8e","after_hash":"062570dfa52d17a58572323282fbbfe5"},{"tool":"trace_from_image","kind":"changed","observed_at":"2026-10-16T03:11:57.227Z","fields":["description","inputSchema"],"description_before":"Use this when you need to trace features from a reference photo into waypoints. Trace pixel-space features from a reference photo into normalized [0..1] waypoints the agent can map to mm via a known scale anchor and feed to path().spline / path().nurbsSegment. Three backends are dispatched behind the scenes: `opencv` (deterministic; uniform-bg silhouette only), `vision-llm` (vision model; named points/cluttered backgrounds; needs ANTHROPIC_API_KEY or an OpenAI-compatible vision endpoint configured on the server), and `hybrid` (opencv silhouette + LLM-labeled named points). Default backend is `auto` — the tool picks based on the image's corner-color stddev. Accuracy honesty: opencv contour is geometrically exact; vision-LLM is typically 5–10% off on dense landmarks. Per-feature `confidence` is reported. Vision-LLM spend is billed to whoever configured the vision model. Pair with the `kernelcad-trace-from-image` skill for the conversion-to-mm pipeline. Hosted: give the file as an https:// URL, a data: URI (base64, max 25 MB) or \"asset:<id>\" from request_upload (when the file is on the user's device).","description_after":"Use this when you need to trace a reference image into normalized waypoints, or turn sketch labels into a catalog-aware draft BOM. Trace pixel-space features from a reference photo into normalized [0..1] waypoints the agent can map to mm via a known scale anchor and feed to path().spline / path().nurbsSegment. Set `detectParts: true` to request labeled component boxes, confidence, bundled-catalog candidates and unmatched labels; the BOM is a draft for review. Three backends are dispatched behind the scenes: `opencv` (deterministic; uniform-bg silhouette only), `vision-llm` (vision model; named points/cluttered backgrounds; needs a configured vision endpoint), and `hybrid` (opencv silhouette + LLM-labeled named points). Default backend is `auto`. Per-feature confidence is reported. Pair with the `kernelcad-trace-from-image` skill for the conversion-to-mm pipeline. Hosted: give the file as an https:// URL, a data: URI (base64, max 25 MB) or \"asset:<id>\" from request_upload (when the file is on the user's device).","description_similarity":0.693,"before_hash":"a2f944bd3cdb8f80b967003d3afa22e7","after_hash":"a8079b43e6422979f52b3725ed670de8"},{"tool":"verify","kind":"changed","observed_at":"2026-10-16T03:11:57.227Z","fields":["description","inputSchema"],"description_before":"Use this when you need to check a design against a rule set. One verifier, selected by `check`:\n- 'assembly' — mate-aware assembly validator on the active session (run evaluate_script first).\n- 'urdf' — structural validity of a .urdf file ({ urdf_path }).\n- 'dfm' — print-readiness gates declared by dfmSpec() ({ file | code }).\n- 'dfm-preflight' — sheet-metal flat pattern vs a job-shop's ordering rules ({ vendor, material, thicknessIn|thicknessMm, ... }). Returns the vendor's catalog source pages as `sources`; when `disclosure` is present, show it with those links.\n- 'assembly-path' — continuous straight-line removal of each assembly part along ±X/±Y/±Z and optional world-space directions. Returns valid directions and blocking parts; disassemblyOrder runs a deterministic greedy removal pass. Watertight mesh approximation, conservative contact, no rotation/mate/hardware certification.\n- 'swept-collision' — sweep declared joint range(s) and report colliding poses.\n- 'reachable' — inverse-kinematics reachability for an end-effector ({ tip_link, target_position, ... }).\n- 'geometry-quality' — one solid body's BREP tiny faces and short edges (ids, locations, mm²/mm), plus sampled mirror symmetry about centroid XY/YZ/XZ and principal inertia planes ({ file | code, feature_id?, tiny_face_area_mm2?, tiny_face_relative?, short_edge_length_mm?, symmetry_tolerance_mm?, mesh_deflection_mm?, asserted_plane?: { origin, normal } }). Relative area is a fraction of total surface area; thresholds are ORed. Candidate planes are discovery; only an asserted plane gates symmetry. Approximate sampled tessellation, not exact BREP proof.\n- 'fastener-installation' — measured explicit catalog-screw installation stations on lowered assembly BREP ({ file | code, fasteners:[{ part, against, engagementPart?, minEngagementMm?, maxProtrusionMm? }], toleranceMm?, angleToleranceDeg? }). Reports annular bearing gap, bore axis/diameter/overlap and receiver geometric engagement/protrusion. Unknown or zero coverage cannot pass. Simplified threads do not certify torque, preload or strength.\n- 'mounting-holes' — fastened mates expose matching hole diameters on both sides.\n- 'load-capacity' — will it hold? Closed-form Euler-Bernoulli beam check ({ loads, materials, ... }), or mode:'fea' to solve the script's feaStudy (quadratic-tet FEA, CalculiX) — both return { ok, safetyFactor, elements[{ partName, stressPa, yieldPa, safetyFactor }], failures[], diagnostics }; fea adds the threshold, the stress regions as @kc[...] faces with their location, and fea { peakStressPa, maxDisplacementMm, meshTrusted, peakAtSupportPa, refinement }; it refines the mesh automatically until the stress is trusted (refine: false for one solve).\n- 'static-hold' — gravitational holding torque/force at a sampled pose grid vs each actuated joint's declared actuator capacity ({ joint?, pose?, gravity?, min_torque_margin_pct?, range_samples? }).\n- 'body-likeness' — publish gate for organic/car bodies: cheap AABB↔wheel checks plus required agent still verdicts (side-body-over-wheels, side-cabin-aft, rear-haunch, ortho-proportions-vs-reference). Pass { body_bbox | code/file+body_feature_id, wheels?, cabin_bbox?, still_verdicts?, require_stills? }. Full CV silhouette matching is NOT implemented — agents must inspect ortho PNGs/Studio and supply still_verdicts before claiming success.\nAll params except `check` are check-specific and forwarded verbatim; each check fails closed on its own missing required params.","description_after":"Use this when you need to check a design against a rule set. One verifier, selected by `check`:\n- 'assembly' — mate-aware assembly validator on the active session (run evaluate_script first).\n- 'urdf' — structural validity of a .urdf file ({ urdf_path }).\n- 'dfm' — print-readiness gates declared by dfmSpec() ({ file | code }).\n- 'dfm-preflight' — sheet-metal flat pattern vs a job-shop's ordering rules ({ vendor, material, thicknessIn|thicknessMm, ... }). Returns the vendor's catalog source pages as `sources`; when `disclosure` is present, show it with those links.\n- 'assembly-path' — continuous straight-line removal of each assembly part along ±X/±Y/±Z and optional world-space directions. Returns valid directions and blocking parts; disassemblyOrder runs a deterministic greedy removal pass. Watertight mesh approximation, conservative contact, no rotation/mate/hardware certification.\n- 'swept-collision' — sweep declared joint range(s) and report colliding poses.\n- 'reachable' — inverse-kinematics reachability for an end-effector ({ tip_link, target_position, ... }).\n- 'geometry-quality' — one solid body's BREP tiny faces and short edges (ids, locations, mm²/mm), plus sampled mirror symmetry about centroid XY/YZ/XZ and principal inertia planes ({ file | code, feature_id?, tiny_face_area_mm2?, tiny_face_relative?, short_edge_length_mm?, symmetry_tolerance_mm?, mesh_deflection_mm?, asserted_plane?: { origin, normal } }). Relative area is a fraction of total surface area; thresholds are ORed. Candidate planes are discovery; only an asserted plane gates symmetry. Approximate sampled tessellation, not exact BREP proof.\n- 'fastener-installation' — measured explicit catalog-screw installation stations on lowered assembly BREP ({ file | code, fasteners:[{ part, against, engagementPart?, minEngagementMm?, maxProtrusionMm? }], toleranceMm?, angleToleranceDeg? }). Reports annular bearing gap, bore axis/diameter/overlap and receiver geometric engagement/protrusion. Unknown or zero coverage cannot pass. Simplified threads do not certify torque, preload or strength.\n- 'mounting-holes' — fastened mates expose matching hole diameters on both sides.\n- 'load-capacity' — will it hold? Closed-form Euler-Bernoulli beam check ({ loads, materials, ... }), or mode:'fea' to solve the script's feaStudy (quadratic-tet FEA, CalculiX) — both return { ok, safetyFactor, elements[{ partName, stressPa, yieldPa, safetyFactor }], failures[], diagnostics }; fea adds the threshold, the stress regions as @kc[...] faces with their location, and fea { peakStressPa, maxDisplacementMm, meshTrusted, peakAtSupportPa, refinement }; it refines the mesh automatically until the stress is trusted (refine: false for one solve).\n- 'static-hold' — gravitational holding torque/force at a sampled pose grid vs each actuated joint's declared actuator capacity ({ joint?, pose?, gravity?, min_torque_margin_pct?, range_samples? }).\n- 'body-likeness' — publish gate for organic/car bodies: cheap AABB↔wheel checks plus required agent still verdicts (side-body-over-wheels, side-cabin-aft, rear-haunch, ortho-proportions-vs-reference). Pass { body_bbox | code/file+body_feature_id, wheels?, cabin_bbox?, still_verdicts?, require_stills? }. Full CV silhouette matching is NOT implemented — agents must inspect ortho PNGs/Studio and supply still_verdicts before claiming success.\n- 'edge-radius' — general edge-break specification on final BREP ({ file | code, min_radius_mm?, max_radius_mm?, require_edge_break?: 'external'|'internal'|'all', feature_id?, assembly?, parts?, edges?, faces? }). Reports sharp convex/concave edges, analytic cylindrical/toroidal fillet radii and spherical junctions, and heuristic planar chamfer strips. Radius bounds apply only to fillets; selectors/points are part-local. Unknown/empty coverage cannot pass.\nAll params except `check` are check-specific and forwarded verbatim; each check fails closed on its own missing required params.","description_similarity":0.919,"before_hash":"36165e7e246177903a40936436fac1aa","after_hash":"490ae4c62c0d185eb0ef302888d1266e"},{"tool":"inspect","kind":"changed","observed_at":"2026-10-16T03:11:57.227Z","fields":["description","inputSchema"],"description_before":"Use this when you need to read facts about a model. One reader, selected by `of`:\n- 'assembly' — physical assembly inventory (parts, bboxes, connectors, mates, disconnected solids).\n- 'robot' — URDF/SDFormat export preview (links, joints, planning groups, end-effectors, issues).\n- 'step' — inspect an imported STEP file: solid tree, exact bbox/volume, cylindrical holes (breached bores flagged partial; holeDetection: 'exact' | 'heuristic').\n- 'shape' — volume / surfaceArea / bbox for one feature ({ feature_id? }).\n- 'mass' — mass, centre of mass, centroidal inertia tensor (inertia6 + 3x3 inertiaMatrix), principalMoments/principalAxes, symmetry flags, and optionally the radius of gyration about an arbitrary axis ({ feature_id?, density?, gyration_axis? }); density in kg/m^3, defaults to 1000 (water).\n- 'features' — features captured by the script (kind, id, params, transforms, suppression).\n- 'assemblies' — assembly intent (assemblies, parts, connectors, joints).\n- 'topology' — canonical face names + edge count for a feature ({ feature_id? }).\n- 'edges' — edges of a shape with optional EdgeQuery ({ feature_id?, query? }); returns @kc[...] refs.\n- 'face-edges' — boundary edges of a named canonical face ({ feature_id?, face_name }).\n- 'faces' — faces of a shape with optional FaceQuery ({ feature_id?, query? }); returns @kc[...] refs.\n- 'face-labels' — user-applied labels visible in the script.\n- 'mates' — mates captured by the script.\n- 'constraints' — sketch constraints captured by the script.\n- 'part-stats' — bundled parts-catalog statistics.\n- 'bend-table' — sheet-metal bend table for a flattened pattern.\n- 'params' — declared model parameters.\n- 'part-categories' — top-level part-catalog categories available in the bundled (and configured remote) catalog.\n- 'part-families' — part families within a category ({ category? }); count + exemplar ids per family.\n- 'bom' — bill of materials ({ assembly? }): one row per distinct part (grouped by geometry/catalog identity, not name) with real instance quantity, kind ('fabricated'|'purchased'), material, density, per-unit and total mass, bbox, a fabrication process hint, catalog provenance for purchased parts, and totals; `bom.*` diagnostics flag rows with no density source or missing catalog vendor info instead of guessing.\n- 'section' — numeric cross-section probe of a shape: area, perimeter, loop/hole counts, 2D bbox at a plane ({ feature_id?, plane | at+axis, stack?: { from, to, count, axis? } }). `stack` scans evenly spaced slices and returns `minAreaIndex`/`minAreaPosition` — use it to find the neck/thinnest cross-section along an axis.\n- 'continuity' — G0/G1/G2 classification of shared edges ({ feature_id?, edges? }); position gap, normal jump, curvature difference, worst-sample XYZ.\n- 'curvature' — per-face Gaussian and mean curvature min/max/mean, inflections, spikes ({ feature_id?, faces?, spike_factor? }).\nAll params except `of` are subject-specific and forwarded verbatim. Most subjects accept { file | code }. Hosted: give the file as an https:// URL, a data: URI (base64, max 25 MB) or \"asset:<id>\" from request_upload (when the file is on the user's device).","description_after":"Use this when you need to read facts about a model. One reader, selected by `of`:\n- 'assembly' — physical assembly inventory (parts, bboxes, connectors, mates, disconnected solids).\n- 'robot' — URDF/SDFormat export preview (links, joints, planning groups, end-effectors, issues).\n- 'step' — inspect an imported STEP file: solid tree, exact bbox/volume, cylindrical holes (breached bores flagged partial; holeDetection: 'exact' | 'heuristic').\n- 'shape' — volume / surfaceArea / bbox for one feature ({ feature_id? }).\n- 'mass' — mass, centre of mass, centroidal inertia tensor (inertia6 + 3x3 inertiaMatrix), principalMoments/principalAxes, symmetry flags, and optionally the radius of gyration about an arbitrary axis ({ feature_id?, density?, gyration_axis? }); density in kg/m^3, defaults to 1000 (water).\n- 'features' — features captured by the script (kind, id, params, transforms, suppression).\n- 'assemblies' — assembly intent (assemblies, parts, connectors, joints).\n- 'topology' — canonical face names + edge count for a feature ({ feature_id? }).\n- 'edges' — edges of a shape with optional EdgeQuery ({ feature_id?, query? }); returns @kc[...] refs.\n- 'face-edges' — boundary edges of a named canonical face ({ feature_id?, face_name }).\n- 'faces' — faces of a shape with optional FaceQuery ({ feature_id?, query? }); returns @kc[...] refs.\n- 'face-labels' — user-applied labels visible in the script.\n- 'mates' — mates captured by the script.\n- 'constraints' — sketch constraints captured by the script.\n- 'part-stats' — bundled parts-catalog statistics.\n- 'bend-table' — sheet-metal bend table for a flattened pattern.\n- 'params' — declared model parameters.\n- 'part-categories' — top-level part-catalog categories available in the bundled (and configured remote) catalog.\n- 'part-families' — part families within a category ({ category? }); count + exemplar ids per family.\n- 'bom' — bill of materials ({ assembly? }): one row per distinct part (grouped by geometry/catalog identity, not name) with real instance quantity, kind ('fabricated'|'purchased'), material, density, per-unit and total mass, bbox, a fabrication process hint, catalog provenance for purchased parts, and totals; `bom.*` diagnostics flag rows with no density source or missing catalog vendor info instead of guessing.\n- 'section' — numeric cross-section probe of a shape: area, perimeter, loop/hole counts, 2D bbox at a plane ({ feature_id?, plane | at+axis, stack?: { from, to, count, axis? } }). `stack` scans evenly spaced slices and returns `minAreaIndex`/`minAreaPosition` — use it to find the neck/thinnest cross-section along an axis.\n- 'continuity' — G0/G1/G2 classification of shared edges ({ feature_id?, edges? }); position gap, normal jump, curvature difference, worst-sample XYZ.\n- 'curvature' — per-face Gaussian and mean curvature min/max/mean, inflections, spikes ({ feature_id?, faces?, spike_factor? }).\n- 'multi-material' — explicit material leaves shadowed by later attributed boolean descendants, with assembly-part rewrite templates; analyzes capture records and does not change mesh attribution.\nAll params except `of` are subject-specific and forwarded verbatim. Most subjects accept { file | code }. Hosted: give the file as an https:// URL, a data: URI (base64, max 25 MB) or \"asset:<id>\" from request_upload (when the file is on the user's device).","description_similarity":0.938,"before_hash":"0d9b081efdf9a458e2ccf7c458af4ae3","after_hash":"e6640a592211dd27c6a214438a489889"},{"tool":"evaluate_script","kind":"changed","observed_at":"2026-10-16T03:11:57.227Z","fields":["description"],"description_before":"Use this when you need to run a script and check it compiles. Full local builds return viewerUrl: a live Studio link reused and updated on later full builds in the same MCP process. Hosted builds return viewerMode: hosted and viewerHint pointing to open_in_studio; they do not start a loopback viewer. Full evaluations return step evidence: build validity, volume and before/after local PNG paths in one shared iso frame. Snapshots require PW_CDP_URL for an existing browser; unavailable captures report an explicit error. Run a kernelCAD .kcad.ts script and report pass/fail + feature count + diagnostics + sceneSummary (BREP validity, volume in mm³, face count, bounding size in mm). When the scene is assembly-built (assembly().part(...) → .model()/.solvedModel()), also returns a parts summary { count, names } AND runs the mechanism-truth gate by default: the `mechanism` field reports real/broken/unverified and a broken mechanism (disconnected components / mechanism.orphan-part, self-collision, fastened drift, dof-mismatch) makes ok:false with the failures in diagnostics — a mechanism (any mate, joint, transmission or .solvedModel()) needs every part linked by connectors + mates/joints (axis+revolute for shafts/hinges/gears; frame+fastened for rigid; or arm.revolute/.prismatic/.ball/.fixed). A plain multi-part assembly with no mates (base + lid, print layout) is independent bodies and passes. Pass { skipMechanismCheck: true } to opt out (e.g. a deliberately free part next to a mechanism). Every union() is checked too (no opt-out): union.disconnected (the union is several separate solids — a floating operand) and union.member-overlap (two operands that each carry their own .finish()/.material(), the same one, share > 1 mm³ — cut members to fit, e.g. a cross tube between rails is span minus two rail widths) make ok:false. Pass either { file: \"<path>\" } or { code: \"<inline source>\" }. Set { dryRun: true } for fast validation while iterating: transpile + capture + capture-light checks without building solids, DFM gates, or meshing — milliseconds instead of seconds (100x+ on boolean/fillet-heavy scripts). A dry run catches script throws, capture-time API misuse, and assembly validity-gate failures, but NOT lowering failures or dfmSpec diagnostics; it leaves the active session untouched, so finish with a full (non-dry) evaluate_script before using session-dependent tools. To show a measurement in the 3D viewer (e.g. hole spacing), declare it in the script with shape.dimension({ kind: \"linear\", from, to, label }); a full evaluate lists them as dimensions: [{ text, kind, source }], and a shared /p link with ?dims=1 forces them on. Hosted: lib.fromSTEP / fromSTL / fromDXF / fromSVG and referenceImage take a direct string literal or a const bound to one (computed expressions are unsupported). They accept \"asset:<id>\" (from request_upload), an https:// URL or a data: URI as the path.","description_after":"Use this when you need to run a script and check it compiles. Full local builds return viewerUrl: a live Studio link reused and updated on later full builds in the same MCP process. Hosted builds return viewerMode: hosted and viewerHint pointing to open_in_studio; they do not start a loopback viewer. Full evaluations return step evidence: build validity, volume and before/after local PNG paths in one shared iso frame. Snapshots require PW_CDP_URL for an existing browser; unavailable captures report an explicit error. Run a kernelCAD .kcad.ts script and report pass/fail + feature count + diagnostics + sceneSummary (BREP validity, volume in mm³, face count, bounding size in mm). When the scene is assembly-built (assembly().part(...) → .model()/.solvedModel()), also returns a parts summary { count, names } AND runs the mechanism-truth gate by default: the `mechanism` field reports real/broken/unverified and a broken mechanism (disconnected components / mechanism.orphan-part, self-collision, fastened drift, dof-mismatch) makes ok:false with the failures in diagnostics — a mechanism (any mate, joint, transmission or .solvedModel()) needs every part linked by connectors + mates/joints (axis+revolute for shafts/hinges/gears; frame+fastened for rigid; or arm.revolute/.prismatic/.ball/.fixed). A plain multi-part assembly with no mates (base + lid, print layout) is independent bodies and passes. Pass { skipMechanismCheck: true } to opt out (e.g. a deliberately free part next to a mechanism). An animation or drive on a fastened joint (mechanism.motion-on-fixed-joint) is broken: animate a revolute/prismatic mate pose. For a model with moving joints or motion intent, `mechanismSummary.statement` is one plain line: \"Motion checked: ...\" names what ran; \"Motion not checked: ...\" is NOT a pass — never call that mechanism working. Every union() is checked too (no opt-out): union.disconnected (the union is several separate solids — a floating operand) and union.member-overlap (two operands that each carry their own .finish()/.material(), the same one, share > 1 mm³ — cut members to fit, e.g. a cross tube between rails is span minus two rail widths) make ok:false. Pass either { file: \"<path>\" } or { code: \"<inline source>\" }. Set { dryRun: true } for fast validation while iterating: transpile + capture + capture-light checks without building solids, DFM gates, or meshing — milliseconds instead of seconds (100x+ on boolean/fillet-heavy scripts). A dry run catches script throws, capture-time API misuse, and assembly validity-gate failures, but NOT lowering failures or dfmSpec diagnostics; it leaves the active session untouched, so finish with a full (non-dry) evaluate_script before using session-dependent tools. To show a measurement in the 3D viewer (e.g. hole spacing), declare it in the script with shape.dimension({ kind: \"linear\", from, to, label }); a full evaluate lists them as dimensions: [{ text, kind, source }], and a shared /p link with ?dims=1 forces them on. Hosted: lib.fromSTEP / fromSTL / fromDXF / fromSVG and referenceImage take a direct string literal or a const bound to one (computed expressions are unsupported). They accept \"asset:<id>\" (from request_upload), an https:// URL or a data: URI as the path.","description_similarity":0.95,"before_hash":"679ed37a042572172afde4616bf01609","after_hash":"0bb4e15e665aa4fc2b155909b35fe1b0"},{"tool":"open_in_studio","kind":"changed","observed_at":"2026-10-16T03:11:57.227Z","fields":["description","outputSchema"],"description_before":"Save the model as a kernelCAD project AND show it: persists a project revision, returns the interactive Studio viewer (MCP Apps / ChatGPT outputTemplate), and includes a PNG preview in the SAME tool result (image content + previewUrl when available). ONE VIEWER PER PROJECT PER RESPONSE: every call renders a new viewer card. Do all validation with evaluate_script first, then call open_in_studio exactly once, after validation succeeds; reuse the returned URL, revision and preview, and never call it again after a successful result in the same response. Re-calling with unchanged code for the same project returns that revision instead of writing a new one. CONTINUE, DO NOT DUPLICATE: to change a model you already saved, pass `project: '<slug>'` from the last result (or from list_my_projects) — this adds a revision to that project. Without `project`, the save goes to the project this chat already saved, or to your project with the same title (case, punctuation and v2/rev3/(1) ignored) from the last 24 h. Views, poses, colours and options of one design are revisions of ONE project — keep the same title and slug. Pass `new_project: true` only when the user wants a separate design. A different cookbook (execute_cookbook, or open_in_studio of that cookbook's unchanged source) starts its own project; pass `project` to add a revision, or `continue_design: true` to keep revising the design this chat is already saving. The result starts with the slug to pass next time, a /p/<slug>?version= link for this revision, and that revision's title. Use this when the user wants to SEE or share the model — do NOT call get_latest_render afterwards for the happy path; the preview is already here when previewDelivered is true. Pass the full `.kcad` source as `code` (optional if you just called evaluate_script — omitting reuses that last evaluated source). Code that fails evaluate_script (for example overlapping same-material members or floating pieces) is refused; fix it first. Multi-body assemblies must declare connectors + mates/joints before publish — otherwise evaluate_script fails with mechanism.orphan-part (disconnected components). Use type: 'axis' + revolute mates for shafts/hinges/gears; type: 'frame' + fastened for rigid mounts; or arm.revolute/.prismatic/.ball/.fixed. Connector types are only frame|axis|planar|ball. Status fields: ok=true means the project revision was saved (projectSaved=true). meshSaved reports whether its display mesh is persisted; meshStatus=failed means meshSaved=false, but the saved project remains usable for geometry checks. Do not claim its 3D viewer is ready. previewDelivered=true means this result carries a displayable PNG — only then may you tell the user a preview was shown. meshStatus mirrors get_project (ready|building|failed|missing). Under CDN, open_in_studio waits up to ~20s (OPEN_IN_STUDIO_MESH_SYNC_BUDGET_MS) for the revision mesh before returning; heavier publishes usually land meshStatus=ready. If still meshStatus=building + meshReady=false: TRANSIENT — meshUrl is the expected CDN pin; embed retries 404s. Poll get_project({slug}) until ready (it shows no viewer) — do not re-call open_in_studio, and never treat building as permanent failure/404. ALWAYS pass `code` when you have it (avoid no_code_to_reuse); evaluate_script reuse is a fallback. Paint phases: projectSaved / meshReady / previewDelivered are set here; viewerPainted is ONLY true after widget ack (model context / widgetState) — never claim paint from this tool alone. Do NOT call get_model_mesh or get_latest_render for interactive paint. INDEPENDENT OF EXPORT/STEP: call this for shaded paint even while export is running, timed out, or returned export.deferred — mesh paint does not wait on STEP. Never block open_in_studio on a STEP download. Pass include_preview:false to skip the rasterizer (save + viewer URLs only). Trigger phrases: \"open it in Studio\", \"let me see it\", \"show me the model\"; also call once after you finish a build, and once per resp","description_after":"Save the model as a kernelCAD project AND show it: persists a project revision, returns the interactive Studio viewer (MCP Apps / ChatGPT outputTemplate), and includes a PNG preview in the SAME tool result (image content + previewUrl when available). ONE VIEWER PER PROJECT PER RESPONSE: every call renders a new viewer card. Do all validation with evaluate_script first, then call open_in_studio exactly once, after validation succeeds; reuse the returned URL, revision and preview, and never call it again after a successful result in the same response. Re-calling with unchanged code for the same project returns that revision instead of writing a new one. CONTINUE, DO NOT DUPLICATE: to change a model you already saved, pass `project: '<slug>'` from the last result (or from list_my_projects) — this adds a revision to that project. Without `project`, the save goes to the project this chat already saved, or to your project with the same title (case, punctuation and v2/rev3/(1) ignored) from the last 24 h. Views, poses, colours and options of one design are revisions of ONE project — keep the same title and slug. Pass `new_project: true` only when the user wants a separate design. A different cookbook (execute_cookbook, or open_in_studio of that cookbook's unchanged source) starts its own project; pass `project` to add a revision, or `continue_design: true` to keep revising the design this chat is already saving. The result starts with the slug to pass next time, a /p/<slug>?version= link for this revision, and that revision's title. Use this when the user wants to SEE or share the model — do NOT call get_latest_render afterwards for the happy path; the preview is already here when previewDelivered is true. Pass the full `.kcad` source as `code` (optional if you just called evaluate_script — omitting reuses that last evaluated source). Code that fails evaluate_script (for example overlapping same-material members or floating pieces) is refused; fix it first. A broken mechanism verdict alone does NOT refuse: the revision is saved, Studio shows \"Mechanism broken\", and the result returns mechanismSummary (statement, maxLevel, failures with the joint). Tell the user the mechanism is broken; do not call it working. Multi-body assemblies must declare connectors + mates/joints before publish — otherwise evaluate_script fails with mechanism.orphan-part (disconnected components). Use type: 'axis' + revolute mates for shafts/hinges/gears; type: 'frame' + fastened for rigid mounts; or arm.revolute/.prismatic/.ball/.fixed. Connector types are only frame|axis|planar|ball. Status fields: ok=true means the project revision was saved (projectSaved=true). meshSaved reports whether its display mesh is persisted; meshStatus=failed means meshSaved=false, but the saved project remains usable for geometry checks. Do not claim its 3D viewer is ready. previewDelivered=true means this result carries a displayable PNG — only then may you tell the user a preview was shown. meshStatus mirrors get_project (ready|building|failed|missing). Under CDN, open_in_studio waits up to ~20s (OPEN_IN_STUDIO_MESH_SYNC_BUDGET_MS) for the revision mesh before returning; heavier publishes usually land meshStatus=ready. If still meshStatus=building + meshReady=false: TRANSIENT — meshUrl is the expected CDN pin; embed retries 404s. Poll get_project({slug}) until ready (it shows no viewer) — do not re-call open_in_studio, and never treat building as permanent failure/404. ALWAYS pass `code` when you have it (avoid no_code_to_reuse); evaluate_script reuse is a fallback. Paint phases: projectSaved / meshReady / previewDelivered are set here; viewerPainted is ONLY true after widget ack (model context / widgetState) — never claim paint from this tool alone. Do NOT call get_model_mesh or get_latest_render for interactive paint. INDEPENDENT OF EXPORT/STEP: call this for shaded paint even while export is running, timed out, or returned export.deferred — mesh paint does not wait on STEP. N","description_similarity":0.977,"before_hash":"774c3e0a6cf1ed192b237d4573fdb4b0","after_hash":"9ebf9115571d871c20ac39e730afb717"},{"tool":"render_preview","kind":"changed","observed_at":"2026-10-15T21:20:26.769Z","fields":["description"],"description_before":"Use this when you need to LOOK at a kernelCAD model — render its script to deterministic PNG views for visual self-check (the visual half of the evaluate → render → inspect → fix loop), with NO studio or dev server required. Pass { code } (inline source) or { file } (a .kcad.ts path), exactly one. Renders the canonical engineering views (front, right, top, iso — pass { views } for a subset, e.g. [\"iso\"] for fastest iteration) plus an optional { pose: \"<az>,<el>\" } arbitrary camera angle (degrees; az=0,el=0 is front, +az rotates CCW around +Z, +el lifts the camera). NO STUDIO / DEV-SERVER REQUIRED: a prebuilt static player (dist/headless-player) is served from an ephemeral local port automatically; a running studio dev server is used as fallback, and { base_url } forces one. The only environment dependency is playwright chromium (npx playwright install chromium). Pass { focus } or { hide } (arrays of feature ids or assembly part names, mutually exclusive) to isolate parts — same semantics as `kernelcad render --focus/--hide`. Pass { section: { axis, position, flip? } } to cut a cross-section and inspect INTERIOR geometry (wall thickness, internal pockets, whether a bore runs through) rather than only the outer shell. Pass { explode: { factor, mode? } } to pull a multi-part assembly apart (mode: \"mate-axis\" default, or \"radial\") using the same mesher as `kernelcad render --explode` — requires assembly.model()/solvedModel(). PNGs are written to { out_dir } (default: a fresh temp session directory) and returned as absolute paths with per-view camera descriptions (kernelCAD is Z-up). Mechanism truth runs first, same protocol as `kernelcad render`: a broken mechanism still renders but every tile is watermarked MECHANISM BROKEN (KERNELCAD_RENDER_STRICT=1 refuses instead); read { mechanism, mechanism_failure_codes }. The probe runs full BREP interference sweeps and can dominate latency on large assemblies — pass { no_mechanism_check: true } for fast iteration (the preview then reports mechanism: \"unverified\"; ignored under strict mode). Pass { overlay: 'zebra' | 'curvature' | 'continuity' } for a surface-quality visualisation (zebra stripes from vertex normals, curvature as vertex colours, continuity edges coloured by G0/G1/G2/broken) — numbers come from inspect({ of: 'continuity' | 'curvature' }); the overlay is the picture. PUBLISH PRESET: pass { preset: 'publish' } for a share-ready studio product shot (gallery tile, social post, README image, product page): key/fill/rim lights + room reflections, soft contact shadow, clean backdrop ({ background: 'white' (default) | 'light' | 'dark' | 'black' | '#rrggbb' | 'transparent' } — transparent gives a PNG with alpha), { shadow: false } to drop the shadow, 2× supersampled anti-aliasing, 30° lens, the model silhouette centred and auto-framed with ~11% air (a script's setCameraTarget is ignored), per-part colours/materials as authored, no watermark. With no views/pose it renders ONE image named 'hero' (3/4 front-right, az=30°, el=22°) at 1600×1200; width/height go up to 2048; views/pose still work under the preset. Output is deterministic for the same input. For a 360° loop use capture_animation({ turntable: true }). INSPECTION SHEET: { sheet: true } renders all seven views (iso, front, back, left, right, top, bottom) and adds one labelled image named 'sheet' tiling them — do not call a model done because it compiled; call it done when every tile of the sheet matches the request. Returns { ok, images: [{ name, path, description }], out_dir, bounds, mechanism, render_source, render_ms, diagnostics }. PATHS ARE LOCAL to the machine running the MCP server — local stdio clients read them directly; hosted/remote clients should use open_in_studio instead.\nHosted server: the PNGs come back IN the result as image content (up to ~1.5 MB total; larger sets are link-only) and each `images[i].url` is an HTTPS link that expires after 24 h. `images[].path` is a server-side path you cannot open. Works with","description_after":"Use this when you need to LOOK at a kernelCAD model — render its script to deterministic PNG views for visual self-check (the visual half of the evaluate → render → inspect → fix loop), with NO studio or dev server required. Pass { code } (inline source) or { file } (a .kcad.ts path), exactly one. Renders the canonical engineering views (front, right, top, iso — pass { views } for a subset, e.g. [\"iso\"] for fastest iteration) plus an optional { pose: \"<az>,<el>\" } arbitrary camera angle (degrees; az=0,el=0 is front, +az rotates CCW around +Z, +el lifts the camera). NO STUDIO / DEV-SERVER REQUIRED: a prebuilt static player (dist/headless-player) is served from an ephemeral local port automatically; a running studio dev server is used as fallback, and { base_url } forces one. The only environment dependency is playwright chromium (npx playwright install chromium). Pass { focus } or { hide } (arrays of feature ids or assembly part names, mutually exclusive) to isolate parts — same semantics as `kernelcad render --focus/--hide`. Pass { section: { axis, position, flip? } } to cut a cross-section and inspect INTERIOR geometry (wall thickness, internal pockets, whether a bore runs through) rather than only the outer shell. Pass { explode: { factor, mode? } } to pull a multi-part assembly apart (mode: \"mate-axis\" default, or \"radial\") using the same mesher as `kernelcad render --explode` — requires assembly.model()/solvedModel(). PNGs are written to { out_dir } (default: a fresh temp session directory) and returned as absolute paths with per-view camera descriptions (kernelCAD is Z-up). Mechanism truth runs first, same protocol as `kernelcad render`: a broken mechanism still renders but every tile is watermarked MECHANISM BROKEN (KERNELCAD_RENDER_STRICT=1 refuses instead); read { mechanism, mechanism_failure_codes }. The probe runs full BREP interference sweeps and can dominate latency on large assemblies — pass { no_mechanism_check: true } for fast iteration (the preview then reports mechanism: \"unverified\"; ignored under strict mode). Pass { overlay: 'zebra' | 'curvature' | 'continuity' } for a surface-quality visualisation (zebra stripes from vertex normals, curvature as vertex colours, continuity edges coloured by G0/G1/G2/broken) — numbers come from inspect({ of: 'continuity' | 'curvature' }); the overlay is the picture. PUBLISH PRESET: pass { preset: 'publish' } for a share-ready studio product shot (gallery tile, social post, README image, product page): key/fill/rim lights + room reflections, soft contact shadow, clean backdrop ({ background: 'white' (default) | 'light' | 'dark' | 'black' | '#rrggbb' | 'transparent' } — transparent gives a PNG with alpha), { shadow: false } to drop the shadow, 2× supersampled anti-aliasing, 30° lens, the model silhouette centred and auto-framed with ~11% air (a script's setCameraTarget is ignored), per-part colours/materials as authored, no watermark. With no views/pose it renders ONE image named 'hero' (3/4 front-right, az=30°, el=22°) at 1600×1200; width/height go up to 2048; views/pose still work under the preset. Output is deterministic for the same input. For a 360° loop use capture_animation({ turntable: true }). INSPECTION SHEET: { sheet: true } renders all seven views (iso, front, back, left, right, top, bottom) and adds one labelled image named 'sheet' tiling them — do not call a model done because it compiled; call it done when every tile of the sheet matches the request. Returns { ok, images: [{ name, path, description }], out_dir, bounds, mechanism, render_source, render_ms, diagnostics }. PATHS ARE LOCAL to the machine running the MCP server — local stdio clients read them directly; hosted/remote clients should use open_in_studio instead.\nHosted server: the PNGs come back IN the result as image content (up to ~1.5 MB total; larger sets are link-only) and each `images[i].url` is an HTTPS link that expires after 24 h. `images[].path` is a server-side path you cannot open. Works with","description_similarity":0.941,"before_hash":"7eb327e599b6b81cfb868a5e5e2f5eed","after_hash":"ebcf59a5be0cbb7f22f17f87d13123ad"},{"tool":"review_cad","kind":"changed","observed_at":"2026-10-15T21:20:26.769Z","fields":["description"],"description_before":"Use this when you need to review a mechanism for fitness and repair mode. Run the deterministic CAD review loop: evaluate the script, validate the assembly/mate graph, check mate connectors touch modeled material, sample declared mate limits, optionally check interferences at sampled poses, report connector workspace bounds, and return a mechanism fitness verdict for agent self-review. Fitness includes repairMode: none, local-fix, parameter-tune, or topology-redesign. Runs within timeBudgetMs (default 90 s): stages that did not fit are listed in skippedStages (their checks did not run; mechanism is then unverified) and stageTimingsMs shows per-stage cost.","description_after":"Use this when you need to review a mechanism for fitness and repair mode. Run the deterministic CAD review loop: evaluate the script, validate the assembly/mate graph, check mate connectors touch modeled material, sample declared mate limits, optionally check interferences at sampled poses, report connector workspace bounds, and return a mechanism fitness verdict for agent self-review. Fitness includes repairMode: none, local-fix, parameter-tune, or topology-redesign. Runs within timeBudgetMs (default 90 s): stages that did not fit are listed in skippedStages (their checks did not run; mechanism is then unverified) and stageTimingsMs shows per-stage cost. Hosted: lib.fromSTEP / fromSTL / fromDXF / fromSVG and referenceImage take a direct string literal or a const bound to one (computed expressions are unsupported). They accept \"asset:<id>\" (from request_upload), an https:// URL or a data: URI as the path.","description_similarity":0.723,"before_hash":"be91157dfd0d860e0bc4a3d77a775760","after_hash":"29ad63f7ae9638703b4872d25618c507"},{"tool":"evaluate_script","kind":"changed","observed_at":"2026-10-15T21:20:26.769Z","fields":["description"],"description_before":"Use this when you need to run a script and check it compiles. Full local builds return viewerUrl: a live Studio link reused and updated on later full builds in the same MCP process. Hosted builds return viewerMode: hosted and viewerHint pointing to open_in_studio; they do not start a loopback viewer. Full evaluations return step evidence: build validity, volume and before/after local PNG paths in one shared iso frame. Snapshots require PW_CDP_URL for an existing browser; unavailable captures report an explicit error. Run a kernelCAD .kcad.ts script and report pass/fail + feature count + diagnostics + sceneSummary (BREP validity, volume in mm³, face count, bounding size in mm). When the scene is assembly-built (assembly().part(...) → .model()/.solvedModel()), also returns a parts summary { count, names } AND runs the mechanism-truth gate by default: the `mechanism` field reports real/broken/unverified and a broken mechanism (disconnected components / mechanism.orphan-part, self-collision, fastened drift, dof-mismatch) makes ok:false with the failures in diagnostics — a mechanism (any mate, joint, transmission or .solvedModel()) needs every part linked by connectors + mates/joints (axis+revolute for shafts/hinges/gears; frame+fastened for rigid; or arm.revolute/.prismatic/.ball/.fixed). A plain multi-part assembly with no mates (base + lid, print layout) is independent bodies and passes. Pass { skipMechanismCheck: true } to opt out (e.g. a deliberately free part next to a mechanism). Every union() is checked too (no opt-out): union.disconnected (the union is several separate solids — a floating operand) and union.member-overlap (two operands that each carry their own .finish()/.material(), the same one, share > 1 mm³ — cut members to fit, e.g. a cross tube between rails is span minus two rail widths) make ok:false. Pass either { file: \"<path>\" } or { code: \"<inline source>\" }. Set { dryRun: true } for fast validation while iterating: transpile + capture + capture-light checks without building solids, DFM gates, or meshing — milliseconds instead of seconds (100x+ on boolean/fillet-heavy scripts). A dry run catches script throws, capture-time API misuse, and assembly validity-gate failures, but NOT lowering failures or dfmSpec diagnostics; it leaves the active session untouched, so finish with a full (non-dry) evaluate_script before using session-dependent tools. To show a measurement in the 3D viewer (e.g. hole spacing), declare it in the script with shape.dimension({ kind: \"linear\", from, to, label }); a full evaluate lists them as dimensions: [{ text, kind, source }], and a shared /p link with ?dims=1 forces them on. Hosted: lib.fromSTEP / fromSTL / fromDXF / fromSVG and referenceImage accept \"asset:<id>\" (from request_upload), an https:// URL or a data: URI as the path.","description_after":"Use this when you need to run a script and check it compiles. Full local builds return viewerUrl: a live Studio link reused and updated on later full builds in the same MCP process. Hosted builds return viewerMode: hosted and viewerHint pointing to open_in_studio; they do not start a loopback viewer. Full evaluations return step evidence: build validity, volume and before/after local PNG paths in one shared iso frame. Snapshots require PW_CDP_URL for an existing browser; unavailable captures report an explicit error. Run a kernelCAD .kcad.ts script and report pass/fail + feature count + diagnostics + sceneSummary (BREP validity, volume in mm³, face count, bounding size in mm). When the scene is assembly-built (assembly().part(...) → .model()/.solvedModel()), also returns a parts summary { count, names } AND runs the mechanism-truth gate by default: the `mechanism` field reports real/broken/unverified and a broken mechanism (disconnected components / mechanism.orphan-part, self-collision, fastened drift, dof-mismatch) makes ok:false with the failures in diagnostics — a mechanism (any mate, joint, transmission or .solvedModel()) needs every part linked by connectors + mates/joints (axis+revolute for shafts/hinges/gears; frame+fastened for rigid; or arm.revolute/.prismatic/.ball/.fixed). A plain multi-part assembly with no mates (base + lid, print layout) is independent bodies and passes. Pass { skipMechanismCheck: true } to opt out (e.g. a deliberately free part next to a mechanism). Every union() is checked too (no opt-out): union.disconnected (the union is several separate solids — a floating operand) and union.member-overlap (two operands that each carry their own .finish()/.material(), the same one, share > 1 mm³ — cut members to fit, e.g. a cross tube between rails is span minus two rail widths) make ok:false. Pass either { file: \"<path>\" } or { code: \"<inline source>\" }. Set { dryRun: true } for fast validation while iterating: transpile + capture + capture-light checks without building solids, DFM gates, or meshing — milliseconds instead of seconds (100x+ on boolean/fillet-heavy scripts). A dry run catches script throws, capture-time API misuse, and assembly validity-gate failures, but NOT lowering failures or dfmSpec diagnostics; it leaves the active session untouched, so finish with a full (non-dry) evaluate_script before using session-dependent tools. To show a measurement in the 3D viewer (e.g. hole spacing), declare it in the script with shape.dimension({ kind: \"linear\", from, to, label }); a full evaluate lists them as dimensions: [{ text, kind, source }], and a shared /p link with ?dims=1 forces them on. Hosted: lib.fromSTEP / fromSTL / fromDXF / fromSVG and referenceImage take a direct string literal or a const bound to one (computed expressions are unsupported). They accept \"asset:<id>\" (from request_upload), an https:// URL or a data: URI as the path.","description_similarity":0.965,"before_hash":"2f10bd9b6fab68cf826860fc4fad1e08","after_hash":"679ed37a042572172afde4616bf01609"},{"tool":"open_in_studio","kind":"changed","observed_at":"2026-10-15T21:20:26.769Z","fields":["description"],"description_before":"Save the model as a kernelCAD project AND show it: persists a project revision, returns the interactive Studio viewer (MCP Apps / ChatGPT outputTemplate), and includes a PNG preview in the SAME tool result (image content + previewUrl when available). ONE VIEWER PER PROJECT PER RESPONSE: every call renders a new viewer card. Do all validation with evaluate_script first, then call open_in_studio exactly once, after validation succeeds; reuse the returned URL, revision and preview, and never call it again after a successful result in the same response. Re-calling with unchanged code for the same project returns that revision instead of writing a new one. CONTINUE, DO NOT DUPLICATE: to change a model you already saved, pass `project: '<slug>'` from the last result (or from list_my_projects) — this adds a revision to that project. Without `project`, the save goes to the project this chat already saved, or to your project with the same title (case, punctuation and v2/rev3/(1) ignored) from the last 24 h. Views, poses, colours and options of one design are revisions of ONE project — keep the same title and slug. Pass `new_project: true` only when the user wants a separate design. A different cookbook (execute_cookbook, or open_in_studio of that cookbook's unchanged source) starts its own project; pass `project` to add a revision, or `continue_design: true` to keep revising the design this chat is already saving. The result starts with the slug to pass next time, a /p/<slug>?version= link for this revision, and that revision's title. Use this when the user wants to SEE or share the model — do NOT call get_latest_render afterwards for the happy path; the preview is already here when previewDelivered is true. Pass the full `.kcad` source as `code` (optional if you just called evaluate_script — omitting reuses that last evaluated source). Code that fails evaluate_script (for example overlapping same-material members or floating pieces) is refused; fix it first. Multi-body assemblies must declare connectors + mates/joints before publish — otherwise evaluate_script fails with mechanism.orphan-part (disconnected components). Use type: 'axis' + revolute mates for shafts/hinges/gears; type: 'frame' + fastened for rigid mounts; or arm.revolute/.prismatic/.ball/.fixed. Connector types are only frame|axis|planar|ball. Status fields: ok=true means the project revision was saved (projectSaved=true). meshSaved reports whether its display mesh is persisted; meshStatus=failed means meshSaved=false, but the saved project remains usable for geometry checks. Do not claim its 3D viewer is ready. previewDelivered=true means this result carries a displayable PNG — only then may you tell the user a preview was shown. meshStatus mirrors get_project (ready|building|failed|missing). Under CDN, open_in_studio waits up to ~20s (OPEN_IN_STUDIO_MESH_SYNC_BUDGET_MS) for the revision mesh before returning; heavier publishes usually land meshStatus=ready. If still meshStatus=building + meshReady=false: TRANSIENT — meshUrl is the expected CDN pin; embed retries 404s. Poll get_project({slug}) until ready (it shows no viewer) — do not re-call open_in_studio, and never treat building as permanent failure/404. ALWAYS pass `code` when you have it (avoid no_code_to_reuse); evaluate_script reuse is a fallback. Paint phases: projectSaved / meshReady / previewDelivered are set here; viewerPainted is ONLY true after widget ack (model context / widgetState) — never claim paint from this tool alone. Do NOT call get_model_mesh or get_latest_render for interactive paint. INDEPENDENT OF EXPORT/STEP: call this for shaded paint even while export is running, timed out, or returned export.deferred — mesh paint does not wait on STEP. Never block open_in_studio on a STEP download. Pass include_preview:false to skip the rasterizer (save + viewer URLs only). Trigger phrases: \"open it in Studio\", \"let me see it\", \"show me the model\"; also call once after you finish a build, and once per resp","description_after":"Save the model as a kernelCAD project AND show it: persists a project revision, returns the interactive Studio viewer (MCP Apps / ChatGPT outputTemplate), and includes a PNG preview in the SAME tool result (image content + previewUrl when available). ONE VIEWER PER PROJECT PER RESPONSE: every call renders a new viewer card. Do all validation with evaluate_script first, then call open_in_studio exactly once, after validation succeeds; reuse the returned URL, revision and preview, and never call it again after a successful result in the same response. Re-calling with unchanged code for the same project returns that revision instead of writing a new one. CONTINUE, DO NOT DUPLICATE: to change a model you already saved, pass `project: '<slug>'` from the last result (or from list_my_projects) — this adds a revision to that project. Without `project`, the save goes to the project this chat already saved, or to your project with the same title (case, punctuation and v2/rev3/(1) ignored) from the last 24 h. Views, poses, colours and options of one design are revisions of ONE project — keep the same title and slug. Pass `new_project: true` only when the user wants a separate design. A different cookbook (execute_cookbook, or open_in_studio of that cookbook's unchanged source) starts its own project; pass `project` to add a revision, or `continue_design: true` to keep revising the design this chat is already saving. The result starts with the slug to pass next time, a /p/<slug>?version= link for this revision, and that revision's title. Use this when the user wants to SEE or share the model — do NOT call get_latest_render afterwards for the happy path; the preview is already here when previewDelivered is true. Pass the full `.kcad` source as `code` (optional if you just called evaluate_script — omitting reuses that last evaluated source). Code that fails evaluate_script (for example overlapping same-material members or floating pieces) is refused; fix it first. Multi-body assemblies must declare connectors + mates/joints before publish — otherwise evaluate_script fails with mechanism.orphan-part (disconnected components). Use type: 'axis' + revolute mates for shafts/hinges/gears; type: 'frame' + fastened for rigid mounts; or arm.revolute/.prismatic/.ball/.fixed. Connector types are only frame|axis|planar|ball. Status fields: ok=true means the project revision was saved (projectSaved=true). meshSaved reports whether its display mesh is persisted; meshStatus=failed means meshSaved=false, but the saved project remains usable for geometry checks. Do not claim its 3D viewer is ready. previewDelivered=true means this result carries a displayable PNG — only then may you tell the user a preview was shown. meshStatus mirrors get_project (ready|building|failed|missing). Under CDN, open_in_studio waits up to ~20s (OPEN_IN_STUDIO_MESH_SYNC_BUDGET_MS) for the revision mesh before returning; heavier publishes usually land meshStatus=ready. If still meshStatus=building + meshReady=false: TRANSIENT — meshUrl is the expected CDN pin; embed retries 404s. Poll get_project({slug}) until ready (it shows no viewer) — do not re-call open_in_studio, and never treat building as permanent failure/404. ALWAYS pass `code` when you have it (avoid no_code_to_reuse); evaluate_script reuse is a fallback. Paint phases: projectSaved / meshReady / previewDelivered are set here; viewerPainted is ONLY true after widget ack (model context / widgetState) — never claim paint from this tool alone. Do NOT call get_model_mesh or get_latest_render for interactive paint. INDEPENDENT OF EXPORT/STEP: call this for shaded paint even while export is running, timed out, or returned export.deferred — mesh paint does not wait on STEP. Never block open_in_studio on a STEP download. Pass include_preview:false to skip the rasterizer (save + viewer URLs only). Trigger phrases: \"open it in Studio\", \"let me see it\", \"show me the model\"; also call once after you finish a build, and once per resp","description_similarity":0.976,"before_hash":"1dc841623d5dd29bcab8887582378a07","after_hash":"774c3e0a6cf1ed192b237d4573fdb4b0"},{"tool":"dfm_review","kind":"added","observed_at":"2026-10-15T15:01:18.054Z","fields":[],"description_before":null,"description_after":"Use this when you need a manufacturability (DFM) report before printing or machining a part: returns a pass/fail checklist, no dfmSpec(...) needed. Pass { file | code } and optional processes (default ['fdm', 'cnc']). FDM 3D printing checks: fdm.overhangs (unsupported overhang steeper than max_overhang_deg, default 45° from vertical), fdm.bridging (bridges over max_bridge_mm, default 10), fdm.min-wall (walls under 2 × nozzle_mm, default 0.4 mm nozzle), fdm.min-hole (holes under 5 × nozzle), fdm.min-pin (warn), fdm.bed-fit (printer profile bed, default generic-fdm), fdm.bed-contact (warn). CNC 3-axis milling checks: cnc.undercuts (surface unreachable from approach_axes, default ['+z']; list several axes for several setups) and cnc.internal-corner-radius (sharp internal corners and fillets smaller than the end-mill radius, tool_diameter_mm default 6). Returns { ok, verdict: 'pass'|'fail', checks: [{ id, process, part, status: 'pass'|'fail'|'warn', summary, value?, limit? }], fdm?, cnc?, diagnostics }. Settings from the script's dfmSpec({ process: 'fdm' }) are used as defaults; call options win. For the script-declared gates (clearance, voids, channels) use verify({ check: 'dfm' }).","description_similarity":null,"before_hash":null,"after_hash":"29937b4bc375bfde79164ebdcefae13a"},{"tool":"fab_pack","kind":"added","observed_at":"2026-10-15T15:01:18.054Z","fields":[],"description_before":null,"description_after":"Use this when the user wants to get a part made: packages the fabrication files into one directory plus a zip, and returns links to public instant-quote pages. Pass { file | code } and output_dir; optional name (default 'part'), formats (default step, stl, 3mf, pdf-drawing, bom-csv; add 'dxf' for flat or sheet parts), and processes ('3d-print' | 'cnc' | 'sheet-cut') to filter the links. Each file is written by the export tool, so its gates apply; a format that fails is reported in files[] and the rest still ship. Also writes manifest.json and README.txt. quote_links lists JLC3DP, JLCCNC, PCBWay, Xometry, SendCutSend and Craftcloud with the pack file to upload to each. These are plain web pages: nothing is uploaded or ordered. The user opens the link and uploads the file. Run dfm_review first if you have not.\nHosted server: pack files are written on the kernelCAD server and returned in downloads[].url; nothing is uploaded to a fabrication service.","description_similarity":null,"before_hash":null,"after_hash":"8f71473c7f97138b3a0a96441f981d68"},{"tool":"verify","kind":"changed","observed_at":"2026-10-15T15:01:18.054Z","fields":["description","inputSchema"],"description_before":"Use this when you need to check a design against a rule set. One verifier, selected by `check`:\n- 'assembly' — mate-aware assembly validator on the active session (run evaluate_script first).\n- 'urdf' — structural validity of a .urdf file ({ urdf_path }).\n- 'dfm' — print-readiness gates declared by dfmSpec() ({ file | code }).\n- 'dfm-preflight' — sheet-metal flat pattern vs a job-shop's ordering rules ({ vendor, material, thicknessIn|thicknessMm, ... }). Returns the vendor's catalog source pages as `sources`; when `disclosure` is present, show it with those links.\n- 'swept-collision' — sweep declared joint range(s) and report colliding poses.\n- 'reachable' — inverse-kinematics reachability for an end-effector ({ tip_link, target_position, ... }).\n- 'fastener-installation' — measured explicit catalog-screw installation stations on lowered assembly BREP ({ file | code, fasteners:[{ part, against, engagementPart?, minEngagementMm?, maxProtrusionMm? }], toleranceMm?, angleToleranceDeg? }). Reports annular bearing gap, bore axis/diameter/overlap and receiver geometric engagement/protrusion. Unknown or zero coverage cannot pass. Simplified threads do not certify torque, preload or strength.\n- 'mounting-holes' — fastened mates expose matching hole diameters on both sides.\n- 'load-capacity' — will it hold? Closed-form Euler-Bernoulli beam check ({ loads, materials, ... }), or mode:'fea' to solve the script's feaStudy (quadratic-tet FEA, CalculiX) — both return { ok, safetyFactor, elements[{ partName, stressPa, yieldPa, safetyFactor }], failures[], diagnostics }; fea adds the threshold, the stress regions as @kc[...] faces with their location, and fea { peakStressPa, maxDisplacementMm, meshTrusted, peakAtSupportPa, refinement }; it refines the mesh automatically until the stress is trusted (refine: false for one solve).\n- 'static-hold' — gravitational holding torque/force at a sampled pose grid vs each actuated joint's declared actuator capacity ({ joint?, pose?, gravity?, min_torque_margin_pct?, range_samples? }).\n- 'body-likeness' — publish gate for organic/car bodies: cheap AABB↔wheel checks plus required agent still verdicts (side-body-over-wheels, side-cabin-aft, rear-haunch, ortho-proportions-vs-reference). Pass { body_bbox | code/file+body_feature_id, wheels?, cabin_bbox?, still_verdicts?, require_stills? }. Full CV silhouette matching is NOT implemented — agents must inspect ortho PNGs/Studio and supply still_verdicts before claiming success.\nAll params except `check` are check-specific and forwarded verbatim; each check fails closed on its own missing required params.","description_after":"Use this when you need to check a design against a rule set. One verifier, selected by `check`:\n- 'assembly' — mate-aware assembly validator on the active session (run evaluate_script first).\n- 'urdf' — structural validity of a .urdf file ({ urdf_path }).\n- 'dfm' — print-readiness gates declared by dfmSpec() ({ file | code }).\n- 'dfm-preflight' — sheet-metal flat pattern vs a job-shop's ordering rules ({ vendor, material, thicknessIn|thicknessMm, ... }). Returns the vendor's catalog source pages as `sources`; when `disclosure` is present, show it with those links.\n- 'assembly-path' — continuous straight-line removal of each assembly part along ±X/±Y/±Z and optional world-space directions. Returns valid directions and blocking parts; disassemblyOrder runs a deterministic greedy removal pass. Watertight mesh approximation, conservative contact, no rotation/mate/hardware certification.\n- 'swept-collision' — sweep declared joint range(s) and report colliding poses.\n- 'reachable' — inverse-kinematics reachability for an end-effector ({ tip_link, target_position, ... }).\n- 'geometry-quality' — one solid body's BREP tiny faces and short edges (ids, locations, mm²/mm), plus sampled mirror symmetry about centroid XY/YZ/XZ and principal inertia planes ({ file | code, feature_id?, tiny_face_area_mm2?, tiny_face_relative?, short_edge_length_mm?, symmetry_tolerance_mm?, mesh_deflection_mm?, asserted_plane?: { origin, normal } }). Relative area is a fraction of total surface area; thresholds are ORed. Candidate planes are discovery; only an asserted plane gates symmetry. Approximate sampled tessellation, not exact BREP proof.\n- 'fastener-installation' — measured explicit catalog-screw installation stations on lowered assembly BREP ({ file | code, fasteners:[{ part, against, engagementPart?, minEngagementMm?, maxProtrusionMm? }], toleranceMm?, angleToleranceDeg? }). Reports annular bearing gap, bore axis/diameter/overlap and receiver geometric engagement/protrusion. Unknown or zero coverage cannot pass. Simplified threads do not certify torque, preload or strength.\n- 'mounting-holes' — fastened mates expose matching hole diameters on both sides.\n- 'load-capacity' — will it hold? Closed-form Euler-Bernoulli beam check ({ loads, materials, ... }), or mode:'fea' to solve the script's feaStudy (quadratic-tet FEA, CalculiX) — both return { ok, safetyFactor, elements[{ partName, stressPa, yieldPa, safetyFactor }], failures[], diagnostics }; fea adds the threshold, the stress regions as @kc[...] faces with their location, and fea { peakStressPa, maxDisplacementMm, meshTrusted, peakAtSupportPa, refinement }; it refines the mesh automatically until the stress is trusted (refine: false for one solve).\n- 'static-hold' — gravitational holding torque/force at a sampled pose grid vs each actuated joint's declared actuator capacity ({ joint?, pose?, gravity?, min_torque_margin_pct?, range_samples? }).\n- 'body-likeness' — publish gate for organic/car bodies: cheap AABB↔wheel checks plus required agent still verdicts (side-body-over-wheels, side-cabin-aft, rear-haunch, ortho-proportions-vs-reference). Pass { body_bbox | code/file+body_feature_id, wheels?, cabin_bbox?, still_verdicts?, require_stills? }. Full CV silhouette matching is NOT implemented — agents must inspect ortho PNGs/Studio and supply still_verdicts before claiming success.\nAll params except `check` are check-specific and forwarded verbatim; each check fails closed on its own missing required params.","description_similarity":0.788,"before_hash":"55577fafd4cf11b055f18e556f1862a6","after_hash":"36165e7e246177903a40936436fac1aa"},{"tool":"import_step","kind":"added","observed_at":"2026-10-15T02:40:24.695Z","fields":[],"description_before":null,"description_after":"Use this when the user wants to start from their own STEP or STL file (a part they designed elsewhere, a vendor model). Give exactly one source: url (a public https direct-download link), upload (a file the user attached in ChatGPT), or content_base64 (raw bytes, small files only). Max 50 MB. The format is detected from the bytes (or pass format: 'step' | 'stl'). Writes the file and a starter <name>.kcad.ts whose base body is lib.fromSTEP / lib.fromSTL into output_dir (default: a fresh temp dir), evaluates it, and returns { ok, format, model_path, script_path, code, bbox }. Pass script_path as { file } to evaluate_script, add_feature, dfm_review, export and the other tools, or edit code to build on the body. STL is a mesh: booleans, bbox and export work, but faces stay planar facets (use mesh_to_features for an editable feature tree). A non-watertight STL is refused unless allow_open is true.","description_similarity":null,"before_hash":null,"after_hash":"3fa5a7ef84ca51923814fc3f135c3c53"}],"next_before":"752336","next_actions":[{"action":"list_changes","description":"Older changes","href":"/v1/servers/com.kernelcad%2Fkernelcad/changes?before=752336&limit=50"}]}