CtrlK
BlogDocsLog inGet started
Tessl Logo

cad-workbench

Use for persistent, visual, short-loop CAD modeling with cad.open, cad.add_part, cad.edit_part, cad.place, cad.import, cad.delete, cad.look, cad.inspect, Host-owned CAD Review, and cad.export.

65

Quality

78%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

Fix and improve this skill with Tessl

tessl review fix ./reference/replicator-original/me/cad-workbench/SKILL.md
SKILL.md
Quality
Evals
Security

CAD Workbench

One document is one scene. The scene holds every part at once, and each action adds to it or changes one part in it; nothing is ever swapped out from under the rest. Model as a sequence of small visible actions. The committed preview is the primary evidence of whether an edit worked.

Scene

A part is one part_id. Its Python cells replay in order and publish the objects that appear in the scene. Every build rebuilds every part, so parts you did not touch stay exactly where they were and stay visible in the preview.

Choose the action from the scene listing that cad.open returns:

  • The part is not in the scene → cad.edit action="add_part". The part_id must be unused.
  • The part is in the scene → cad.edit action="edit_part".
  • A board or purchased STEP file → cad.edit action="import".

cad.edit action="add_part" refuses an existing part_id and cad.edit action="edit_part" refuses a missing one, so neither can quietly replace a part already in the scene. Object ids must be unique across the whole scene, not just within one part.

Placement

Model each part in its own frame — centred or on its own base plane — and assemble with cad.edit action="place", rather than writing assembly offsets into the Python. Placement is a document value: cad.edit action="place" sets an object's absolute position and rotation and commits a normal build without changing a single cell, so a later cad.edit action="edit_part" reshapes the part and leaves it exactly where you put it.

Placement is rigid. Pass the position you want, not a delta, and change the part's parameters when you need it bigger; a scaled placement is rejected. The desktop placement fields commit this same action, so a user drag and an agent call are the same build-bound edit.

Loop

  1. Call cad.open and retain buildNumber. Read its scene listing; it decides which action comes next. Use the explicit cad.readme.update tool whenever the design's README must be created or replaced, then call cad.status because this changes state identity without changing geometry build.
  2. If the document already has a build, inspect the current preview attached by cad.open before editing. A new root document has no model to preview yet.
  3. Call cad.edit action="add_part" or cad.edit action="edit_part" with exactly one small Python cell. Every part must expose its user-editable dimensions with param() or the action is rejected. Never reference cache files directly from Python.
  4. Inspect the attached preview directly before doing anything else. A new part must appear alongside the parts that were already there; if the preview shows anything else, stop and read the scene with cad.inspect before continuing.
  5. If the image exposes a problem, make one focused repair with another cad.edit action="edit_part" call using the new Build number.
  6. If the last direction is not worth repairing, reopen the current exact build and replace the affected stable cell with a focused correction.

Keep the loop short. Do not write a large one-shot script, speculate through many hidden edits, or defer visual inspection until the end.

If cad.open reports previewError, the Build number and source are still available. Do not make a blind design change. Read the affected part with cad.inspect({ kind: "source", ... }), then re-run the exact current cell through cad.edit action="edit_part" without changing its code to recover a committed preview, or report the damaged observation state.

Python Cell Contract

Build123d symbols are already available. Publish each visible object explicitly:

body = Box(40, 30, 12)
publish("body", body, "Main body")

Parameterization is mandatory for every part added with cad.edit action="add_part" or changed with cad.edit action="edit_part". Expose all dimensions a user may reasonably adjust: overall length/width/height, wall or plate thickness, hole/slot diameter or size, and independently adjustable feature positions. A zero-parameter part cannot be committed. Imported vendor or PCB STEP assets are exempt because they use cad.edit action="import".

Use stable parameters:

body_width = param("body_width", 40.0)
mount_hole_diameter = param("mount_hole_diameter", 3.2)
body = Box(body_width, 30, 12)

Use one parameter for each independently editable feature. For example, separate left and right hole diameters when the user may change them independently. Existing parameters can be changed with cad.edit action="set_parameter"; the CAD drawing UI uses the same build-bound action.

A parameter is a number the user owns. Anything fixed by an external standard, a purchased part, or an imported asset stays a plain named constant with a comment naming its source, and anything derived stays an expression:

PCB_THICKNESS_MM = 1.6           # JEDEC/mITX board stock, not a user choice
DIMM_PITCH_MM = 8.0              # DDR5 DIMM connector pitch

wall = param("wall_thickness", 2.4)
inner_width = param("inner_width", 120.0)
outer_width = inner_width + 2 * wall   # derived, not its own parameter

Keep the list readable in one pass — roughly a dozen per part is normal, a few dozen is already a lot. Past that, check whether reference geometry leaked in, whether derived values were parameterized separately, or whether the part should be split. The outliner shows the count next to Parameters, and a part with hundreds of them is unusable in the UI even though it commits.

Use a stable short object_id and a short UI label (about 2–6 words), for example top_cap / Top cap. The scene outliner shows these labels; do not put long prose, fastener specs, or full design rationale into the publish label.

Cells on the same part replay in order and share names. A part's first cell is named after the part itself. In cad.edit action="edit_part", use a stable cell id to replace that cell; use after when inserting a new one. Load build123d-core only when specific API syntax or modeling details are needed.

The imports target is reserved for cad.edit action="import". Never address it with cad.edit action="add_part" or cad.edit action="edit_part"; imported geometry, asset hashes, and provenance must remain one managed unit.

Deleting

cad.edit action="delete" removes source, not published geometry. Delete one cell with { target, cell }, or a whole target with { target } alone; the objects those cells published disappear with them. Deleting the last cell of a target deletes the target too. Use cad.edit action="delete" on the imports target to drop a wrong or superseded cad.edit action="import": the imported STEP is unbound from the document in the same build. A target that other targets depend on cannot be deleted while those dependents exist. Deletion commits a normal build and requires a handoff cad.export before the query ends. Use the query-level Undo action when the change itself must be reverted.

Project PCB inputs

When the project has a PCB, read the current PCB Release manifest, its real package/assembly.step, editable placement/board source, source/pcb.config.json, and applicable product or hardware files before modeling around it. Use cad.edit action="import" for that STEP. A recognized project PCB release is verified and stored automatically as assets[].provenance.pcbRelease; the CAD export receipt repeats it in stateManifest.pcbReleases.

Read referenced project PDFs with pdf.search, pdf.read, or pdf.render_pages as appropriate. Paths such as product/references/<document>.pdf name PDF artifacts stored in the workspace and are accepted directly by those tools. Use fs.glob to locate them when needed; use the PDF tools to read their contents.

On an existing document, compare the recorded PCB Release from cad.open with the current PCB Release before editing or exporting. Inspect actual changes before deciding whether CAD work is needed:

  • Board geometry, mounting, enclosure-facing component placement or height, openings, controls, acoustic paths, cable access, thermal space, and clearances can affect the model.
  • Copper-only routing, vias, pours, labels, and firmware changes normally leave the model compatible.
  • Internal component movement matters when it reaches an enclosure-dependent clearance or feature.

When affected, state the changed PCB feature and the corresponding CAD feature. When compatible, keep the CAD geometry unchanged.

Observation Rules

  • Trust the attached image for shape, proportion, composition, interfaces, and visible defects.
  • Use cad.look to bring the exact committed preview back into context.
  • Each object renders in its own colour, so read the assembly view for placement and interfaces between parts.
  • To judge one part's own geometry, call cad.look with isolate: ["<object_id>"]. It renders those objects alone and frames the camera on them.
  • To judge how a part sits in the assembly, add context: "ghost". The surrounding objects stay as outlines, so an internal part is visible without losing its placement.
  • To see past a shell, cover, or lid, hide it instead of isolating everything underneath.
  • An isolated or hidden view is evidence only about what it shows. Do not conclude anything about a part you removed from the image.
  • Use cad.inspect with kind: "selection" for a picked face/edge/shape's surface type, center, normal or axis, radius, area/length, bounds, and adjacency.
  • Use cad.inspect with kind: "measure" for exact distance, axis distance, angle, radius, or diameter. Pass build-bound selection refs from the current model; add expect only when a real requirement supplies the target and tolerance.
  • Use cad.inspect with kind: "analysis" and analyses: ["geometry"] for object-level extents, topology counts, and major planar face groups. Build comparison also reports topology and geometry deltas for changed objects.
  • Bounding boxes and similar detectors are information only. They never prove that the model looks right or satisfies the intent.
  • Do not declare success from a successful kernel build alone. A valid B-rep can still be the wrong object.
  • Call cad.export with intent: "handoff" on the exact finished build before ending every query that changes CAD geometry, parameters, imported assets, or the review brief. This applies to visual_review documents too. The Host runs the independent CAD Review automatically and returns findings when another build is required. A handoff publishes STEP only, and the app derives the current GLB preview from that STEP. A committed build without a matching STEP export is review-required or export-required, never ready. Do not add STL, 3MF, or GLB to the CAD artifact contract.

Build Discipline

Every write requires the exact buildNumber returned by the preceding open, generate, import, or delete. If a stale_build error occurs, call cad.open, inspect the current state, and continue from that version.

Repository
JimmyPang02/open-replicator
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.