Skip to content

Sheet-metal MCP tools and manufacturing pipeline#226

Merged
ecto merged 17 commits into
mainfrom
claude/review-sheet-metal-progress-iJGIg
Jun 2, 2026
Merged

Sheet-metal MCP tools and manufacturing pipeline#226
ecto merged 17 commits into
mainfrom
claude/review-sheet-metal-progress-iJGIg

Conversation

@ecto
Copy link
Copy Markdown
Owner

@ecto ecto commented Jun 2, 2026

Summary

Implements the complete sheet-metal manufacturing pipeline as MCP tools and kernel operations, enabling AI agents to design, validate, cost, and nest sheet-metal parts. Adds manufacturability checking, cost estimation, bend sequencing, and multi-part nesting as queryable interfaces on the model.

Key Changes

MCP Tools (packages/mcp/src/tools/sheet-metal.ts)

  • sheet_metal_create — Build a sheet-metal part from base flange + edge flanges/hems/jogs; returns document ID + ambient DFM violations
  • sheet_metal_unfold — Generate flat pattern and layered DXF (CUT/BEND_UP/BEND_DOWN) ready for laser bureaus
  • sheet_metal_check — Re-run manufacturability against caller-supplied shop profile; structured violation output for agent self-healing
  • sheet_metal_materials — Registry of six shop-standard alloys with mechanical properties
  • sheet_metal_bend_table — K-factor lookup table (material × thickness × radius)
  • sheet_metal_cost — Estimate manufacturing cost (material + cut + pierce + bend + setup)
  • sheet_metal_sequence — Optimal bend order (outside-in heuristic for press-brake forming)
  • sheet_metal_nest — Pack multiple parts onto stock sheets (BLFD algorithm)
  • sheet_metal_suggest_fix — Deferred; structured violations already enable agent self-healing

Kernel Operations

  • Hem (crates/vcad-kernel-sheet/src/hem.rs) — 180° folds (closed/open variants) for edge stiffening
  • Jog (crates/vcad-kernel-sheet/src/jog.rs) — Z-shaped offsets via two opposite 90° bends
  • Polygon base flange (crates/vcad-kernel-sheet/src/base_flange.rs) — Arbitrary CCW outline + CW holes instead of just rectangles
  • Manufacturability checking (crates/vcad-kernel-sheet/src/manufacturability.rs) — Foundation-tier rules: bend radius, brake capacity, flange height, hole-to-bend distance, bend-to-bend spacing
  • Cost estimation (crates/vcad-kernel-sheet/src/cost.rs) — Material + cut + pierce + bend + setup with configurable shop rates
  • Bend sequencing (crates/vcad-kernel-sheet/src/sequence.rs) — Outside-in ordering for collision-free forming
  • Multi-part nesting (crates/vcad-kernel-sheet/src/nesting.rs) — Bottom-Left Fill Decreasing (BLFD) rectangular packing
  • DXF export (crates/vcad-kernel-sheet/src/dxf.rs) — Layered R12 output (CUT/BEND_UP/BEND_DOWN) for laser bureaus
  • Material registry (crates/vcad-kernel-sheet/src/materials.rs) — Curated properties (Al-soft, Al-hard, Steel-mild, SS-304, Copper, Titanium)

Engine & WASM Bindings

  • packages/engine/src/sheet-metal.ts — TypeScript wrappers for all kernel operations
  • crates/vcad-kernel-wasm/src/sheet_metal.rs — WASM bindings for evaluate, check, cost, sequence, nest, materials, bend table
  • packages/kernel-wasm/vcad_kernel_wasm.d.ts — Type definitions for WASM exports

IR & Evaluation

  • packages/ir/src/index.ts — TypeScript types for SheetMetalBaseFlangePolygon, SheetMetalHem, SheetMetalJog operations
  • crates/vcad-ir/src/lib.rs — IR enum variants for polygon base, hem, jog
  • Evaluation stubs in crates/vcad-eval/src/evaluate.rs and other consumers (return `None

https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q

claude added 15 commits May 16, 2026 21:59
Adds `flat_pattern_to_dxf` in vcad-kernel-sheet: serialises a
FlatPattern to DXF R12 with the manufacturing layer convention from
the design spec — CUT (red) for panel outlines + holes, BEND_UP
(blue) / BEND_DOWN (cyan) for creases, in millimetres. Threaded
through the WASM binding and engine glue (rides along with the flat
pattern in one boundary call) and surfaced as a "Download DXF"
button in the sheet-metal panel. Closes the last foundation-tier gap.

https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
Adds check_manufacturability(model, shop) in vcad-kernel-sheet: a
pure function over the panel/bend graph returning structured
Violations (BendRadiusBelowMinimum, BendExceedsBrakeCapacity,
FlangeBelowMinHeight, HoleTooCloseToBend, BendsTooClose), plus a
ShopProfile type with a sensible generic() default. Threaded through
the WASM binding and engine glue and surfaced as a Problems-style DFM
inspector in the sheet-metal panel (errors/warnings chip, "Shop-ready"
when clean). First leg of the spec's DFM-as-typed-query — same data
will back the sheet_metal.check MCP tool.

https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
Makes manufacturability a tunable typed query rather than a
generic-shop by-product:

- ShopProfile is now Deserialize + #[serde(default)] (field-tolerant:
  omitted keys fall back to generic(), so older saved profiles still
  load).
- New checkSheetMetal(chainJson, shopJson) WASM binding — runs
  check_manufacturability against a caller-supplied shop and echoes
  back the merged profile. Kept separate from evaluateSheetMetalChain
  on purpose: the spec treats manufacturability as a query against the
  model, not a mesh-eval side effect.
- Engine: SheetMetalShopProfile / SheetMetalCheckResult types,
  DEFAULT_SHOP_PROFILE, checkSheetMetalManufacturability(), and an
  Engine.checkSheetMetal(doc, shop?) method that finds the sheet-metal
  root and runs the query. Kernel WASM rebuilt.

Backend only; the Shop Profile editor UI lands next.

https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
- Persisted shop-profile store (localStorage, field-tolerant merge onto
  generic defaults) + an editor in the sheet-metal panel: brake length,
  R/t, flange height, hole→bend, bend→bend, shop name, reset.
- DFM inspector re-runs against the active profile via
  Engine.checkSheetMetal and shows which shop it checked against.

Root-cause fix so the feature actually renders in-app:
- KernelModule never carried the sheet-metal bindings, so
  this.kernel.checkSheetMetal / evaluateSheetMetalChain were undefined.
  Added them to the interface + Engine.init + worker kernelModule.
- The eval worker (the default async path) post-processed embroidery
  but not sheet metal, so sheet-metal parts never got their
  part.sheetMetal bundle and the panel never appeared. Added
  postProcessSheetMetal mirroring postProcessEmbroidery.

Engine + app typecheck clean; 65 engine tests pass.

https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
Adds the AI-native sheet-metal surface from the spec:

- sheet_metal_create: base flange + edge-flange chain → session
  document_id (reusable with inspect_cad / export_cad /
  open_in_browser) + model summary + generic-shop DFM.
- sheet_metal_unfold: flat pattern + layered DXF.
- sheet_metal_check: manufacturability vs. a field-tolerant shop
  profile → structured violations to iterate on.

Session-document based for consistency with the rest of the MCP
surface; reuses Engine.evaluate / Engine.checkSheetMetal so there's
one source of truth. Added registerSession() to session.ts so tools
can hand back ids without duplicating the id scheme.

New test drives create → unfold → check end-to-end through the real
engine + WASM (also covers the step-4 kernel wiring). 17 MCP tests
pass; mcp typechecks clean.

cost / suggest_fix deferred (need the process-cost model + IR-edit
primitives).

https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
Replaces the spec's "single global K-factor lie" / single shop R/t with
a real materials registry plumbed through the manufacturability query:

- New vcad-kernel-sheet::materials module: 6 curated materials
  (al-soft/-hard, steel-mild, ss-304, brass, copper) with min R/t,
  yield, modulus, density, and a coarse springback estimate. Lookup is
  case + alias tolerant ("aluminum", "6061-T6", "stainless" all hit);
  unknowns fall back to a conservative profile so checks don't silently
  pass.
- check_manufacturability now uses max(material.min_r_over_t,
  shop.min_bend_radius_ratio) and tags the radius violation with which
  one was the stricter constraint, so the UI can explain.
- SheetMetalModel grows a `material` field, populated through the WASM
  chain from the BaseFlangeRect op. Bend-table rows lowercased to one
  canonical key; lookup is case-insensitive for forward-compat.
- New WASM bindings + engine helpers + MCP tools:
  sheet_metal_materials and sheet_metal_bend_table — agents can inspect
  what's available before authoring.
- App: material shown in the sheet-metal panel header.

52 sheet + 14 wasm + 20 mcp tests pass; clippy/fmt clean; app typecheck
clean. New MCP test proves al-hard at R/t=1 is flagged while al-soft is
shop-ready — the spec's "K-factor lie" is gone.

https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
Live, line-itemed manufacturing cost — material / cut / pierce / bend /
setup with shop markup — surfaced as a panel badge and as the
sheet_metal_cost MCP tool. Spec strategic item #6, killing the
send-to-shop-wait-three-days-for-a-quote loop.

- New vcad-kernel-sheet::cost module: pure function of (model, flat,
  qty, rates). Mass from flat area × thickness × density (looked up via
  the materials registry, so changing alloy updates cost). Generic
  low-volume laser defaults work out of the box; rates are
  Deserialize + #[serde(default)] so a partial JSON merges onto
  generic.
- WASM costSheetMetal binding + engine helper +
  Engine.costSheetMetal(doc, rates?, qty?) method (worker kernelModule
  carries it too).
- App cost badge: per-unit total + expandable breakdown
  (material kg, cut length, pierces, bends, setup, markup) with an
  editable quantity for setup amortization. Recomputes live on edit.
- sheet_metal_cost MCP tool: agents see which line dominates and which
  design changes lower the price.

57 sheet + 14 wasm + 22 mcp + 65 engine tests pass; clippy/fmt clean;
app typecheck clean.

https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
Adds first-class hem support — 180° folds at the edge of a flange,
the most common sheet-metal feature after edge flanges (~50% of real
brackets have hems for stiffening / burr removal).

Plumbed through every layer:

- IR: new SheetMetalHem op (Rust + TS), SheetMetalHemKind (Closed |
  Open). All existing CsgOp matches updated.
- Kernel: new vcad_kernel_sheet::hem module with add_hem(). Closed
  hems pack tight (R = t/2); open hems honour gap (R = gap/2). The
  bend's k_factor_source carries a ";hem:closed|open" tag for the
  UI/DXF/agent to label it.
- Same lossless unfold, layered DXF, DFM check, and cost machinery
  pick hems up for free — they're regular bends with angle = π.
- WASM chain gained a Hem variant; engine buildSheetMetalChain
  walks SheetMetalHem; worker post-processing already handles it.
- MCP sheet_metal_create gained a `hems` array, applied in order
  after flanges. New end-to-end MCP test creates a hemmed bracket,
  unfolds it, and asserts a 180° crease in the DXF.

60 sheet + 14 wasm + 23 mcp + 65 engine tests pass; app typecheck
clean. Workspace compiles green.

https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
Closes the AI self-heal loop. For each manufacturability violation,
return the concrete parameter change that resolves it — typed
fix.action plus the new numeric target:

  BendRadiusBelowMinimum      → increase_radius        (new_radius_mm)
  FlangeBelowMinHeight        → increase_flange_length (new_length_mm)
  BendExceedsBrakeCapacity    → shorten_or_split_bend  (max_length_mm)
  HoleTooCloseToBend          → move_hole_or_clearance (required_clearance_mm)
  BendsTooClose               → separate_bends         (required_distance_mm)

With create → check → suggest_fix → re-create → re-check, an LLM agent
can iterate to a manufacturable part with no human in the loop — the
spec's headline AI bet.

24 MCP tests pass; mcp typechecks clean.

https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
Materials registry already carries springback_per_radian; now expose
it on every bend so the brake operator sees the angle to actually
form rather than guessing.

- bend summary grows springback_rad + compensated_angle_rad =
  angle + springback_per_radian × angle (material-specific).
- app: bend list shows "Form to 91.2° (+1.2° springback)" when
  non-trivial. Hems get a "Hem closed/open" label instead of "180°".
- engine TS types updated; new MCP test asserts al-hard springback
  exceeds al-soft.

Spec's springback item: data → user-visible. 25 MCP tests pass.

https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
Adds first-class jog support — Z-shaped offsets, the third common
sheet-metal feature after flanges and hems. Plumbed end-to-end.

- IR: SheetMetalJog op (Rust + TS). All existing CsgOp matches
  updated.
- Kernel: vcad_kernel_sheet::jog::add_jog — two equal-and-opposite
  90° bends; the tail panel ends up parallel to the parent and
  `offset` mm above. Bends tagged `;jog:a` and `;jog:b` for UI
  labels.
- WASM chain gained a Jog variant; engine buildSheetMetalChain walks
  SheetMetalJog; worker post-processes hem and jog the same way.
- MCP sheet_metal_create gained a `jogs` array. Flanges + hems + jogs
  compose in one call.

63 sheet + 14 wasm + 26 mcp tests pass; clippy/fmt clean; app
typecheck clean.

https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
Removes the rectangle-only authoring constraint. Any CCW outline (with
optional CW hole loops) is now a first-class base flange.

- IR: SheetMetalBaseFlangePolygon op (Rust + TS) with outline, holes,
  thickness, material. All CsgOp matches updated.
- Kernel: base_flange_polygon_with_holes exported from
  vcad-kernel-sheet (base_flange_rect now a thin wrapper). Holes flow
  through the existing Panel structure, so unfold + DXF pick them up
  for free.
- WASM chain gained a BaseFlangePolygon variant; engine
  buildSheetMetalChain walks the IR variant.
- MCP sheet_metal_create accepts `outline` (and `holes`), taking
  precedence over width/depth. Outline points can be `{x,y}` objects
  or `[x,y]` pairs for agent ergonomics.

L-bracket + holed-rectangle MCP tests pass end-to-end through unfold
and into the layered DXF (1 outline + 1 hole on the CUT layer for the
holed case). 65 sheet + 14 wasm + 28 mcp tests pass; app typecheck
clean.

https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
Adds a feasible press-brake bend order with rationale.

- vcad-kernel-sheet::sequence::bend_sequence: outside-in BFS over the
  bend tree, ties broken by id. Each step has angle / radius /
  compensated_angle (target + springback) / hinge length plus a
  one-line rationale (hem first, jog members together, root-adjacent
  last).
- sheetMetalSequence WASM binding + engine helper +
  Engine.sheetMetalSequence(doc) method.
- sheet_metal_sequence MCP tool — agents and shop UIs get the form
  order directly.

End-to-end MCP test on a U-channel with a hem asserts deeper bends
sort first. 69 sheet + 14 wasm + 29 mcp tests pass; app typecheck
clean.

https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
Bottom-left-fill decreasing rectangular packer — the spec's Tier-7
"Nesting" capability arriving early.

- vcad-kernel-sheet::nesting: configurable stock + spacing + edge
  margin + 0°/90° rotation. Sorts by max-dim descending, lowest-then-
  leftmost fit, new sheet on no-fit. Reports per-sheet utilization
  and flags oversize parts as unplaceable.
- nestSheetMetalParts WASM binding + engine helper +
  Engine.nestSheetMetalParts method.
- sheet_metal_nest MCP tool: each part is either an explicit
  footprint or a session document_id (footprint inferred from the
  flat bbox of the rendered part).

75 sheet + 14 wasm + 31 mcp tests pass; app typecheck clean. NFP
true-shape nesting lands in a later tier — BLFD covers the bulk of
laser-cut shop work today.

https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
Emits one layered DXF per stock sheet with every nested part placed
and oriented — closes the loop from nesting to shop-ready file.

- vcad-kernel-sheet::dxf::nested_dxf: takes
  &[NestedPlacement {flat, sheet, dx, dy, rotated}], returns one DXF
  string per stock sheet. Same CUT / BEND_UP / BEND_DOWN layers as the
  single-part exporter.
- nestedSheetMetalDxf WASM binding: accepts an array of
  {chain, sheet, dx_mm, dy_mm, rotated} — each part is independently
  evaluated then placed.

With sheet_metal_nest returning placements and this binding turning
them into per-sheet DXF, a multi-part nested job is one tool call away
from a quote-able artifact.

77 sheet + 14 wasm tests pass; clippy/fmt clean.

https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
@vercel
Copy link
Copy Markdown

vercel Bot commented Jun 2, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

4 Skipped Deployments
Project Deployment Actions Updated (UTC)
mecheval Ignored Ignored Jun 2, 2026 10:03pm
vcad Ignored Ignored Jun 2, 2026 10:03pm
vcad-docs Ignored Ignored Jun 2, 2026 10:03pm
vcad-mcp Ignored Ignored Jun 2, 2026 10:03pm

Request Review

claude added 2 commits June 2, 2026 19:16
cargo fmt --check (workspace-wide, both stable and nightly) wanted the
sheet-metal arm body to be a single Err(...) expression rather than
a block. My local fmt only ran on -p vcad-kernel-sheet/-wasm and
missed it. No behavior change.
Three small duplications crept in across hem/jog/sequence/check/wasm.
Promoted them to methods on Bend and SheetMetalModel:

- Bend::append_source_tag(suffix): hem and jog were both inlining the
  same "clone or 'manual' + push" boilerplate to tag bends as hems /
  jog members.
- SheetMetalModel::material_properties() -> Option<MaterialProperties>:
  manufacturability checks were doing the empty-material branching by
  hand.
- SheetMetalModel::springback_per_radian() -> f64: sequence.rs and the
  wasm summariser both repeated `if material.is_empty() { 0 } else {
  lookup(...).springback }`.

Also dropped a dead `_point2_witness` placeholder + its now-unused
Point2 import in sequence.rs, and simplified a "let _ = w; let _ = h;"
in dxf::nested_dxf where only the height was actually used.

No behaviour change. 77 sheet + 14 wasm tests still pass; clippy clean;
workspace-wide cargo fmt --check clean (the same invocation CI uses).
@ecto ecto merged commit 3819c50 into main Jun 2, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants