FluidCAD
GitHubFluidCAD参数化3D建模技能,指导通过MCP服务器进行零件设计、编辑与修改。涵盖草图、特征操作及导出流程,强调查阅文档与并行子代理协作以确保API准确性。
Trigger Scenarios
Install
npx skills add Fluid-CAD/FluidCAD --skill FluidCAD -g -y
SKILL.md
Frontmatter
{
"name": "FluidCAD",
"description": "Workflow and best practices for designing parts in FluidCAD through its MCP server. Use this skill whenever the user wants to model, design, build, edit, fix, or modify any part in FluidCAD, whenever they mention FluidCAD, a `.fluid.js` or `.part.js` file, or ask for CAD, parametric modeling, or 3D printing work that involves sketches, constraints, extrudes, cuts, revolves, sweeps, lofts, fillets, chamfers, shells, holes, bosses, ribs, patterns, repeats, mirrors, faces, edges, shape filters, measuring, STEP or STL export. Trigger this even if the user does not explicitly say \"FluidCAD\": any time the FluidCAD MCP tools (`mcp__FluidCAD__*`) are available and the task involves 3D part design, follow this skill."
}
Provenance: maintained in the FluidCAD repo (https://github.com/Fluid-CAD/FluidCAD), under mcp/skills/. The installed local skill files are the runtime source of truth.
FluidCAD modeling workflow
You are driving a live FluidCAD workspace through the FluidCAD MCP. The MCP is the source of truth: for the API, for what is in the scene, and for whether the latest edit compiled and built. Lean on it instead of guessing.
Before touching the scene
- Find the workspace. Call
list_workspacesfirst so you know which workspace and which file you are editing. - Read the docs for what you intend to use. Even if you "know" how
sketch,extrude,cut,revolve,repeat,filletor a filter works, callsearch_docs/read_doc/get_api_signaturebefore using it. The API evolves; assumptions from past sessions are the usual source of compile errors and wasted iterations. - Resolve unfamiliar types. When a signature mentions a type you do not fully understand (
PlaneLike,AxisLike,SceneObject,LinearRepeatOptions), callget_type_definitionon it. Do not guess at accepted forms. - Read the concept doc before a new concept. Sketch constraints, filter chaining, repeats, parameters, units: a few seconds of
read_docis cheaper than a failed render.
Send sub-agents into the docs, in parallel
If your client can run sub-agents, turn that reading into one agent per API area and launch them concurrently, so the API knowledge is waiting when you start writing code.
- Two waves, so the reading overlaps the thinking. The baseline (sketching and the 2D primitives,
extrudeandcut, plane and face references) is needed by almost every part: launch it as soon as you know roughly what the part is. Once the plan names its operations, launch one agent per operation mapped to its FluidCAD counterpart: revolved feature torevolve, patterned holes torepeat, edge break tofillet/chamfer, hollowing toshell, swept or lofted geometry tosweep/loft, plus the face and edge filters the plan's selections will need. - Launch each wave in a single message so its agents actually run concurrently.
- One agent per API area, not per doc page. Each returns a compact digest: the exact signature verbatim from
get_api_signature, every type in it resolved viaget_type_definition, one minimal snippet with its imports, and the documented gotchas and limitations, including anything the docs say is not supported. - Sub-agents read, they never build. No
write_file,edit_range,recomputeorrollback_to. The MCP drives one live scene; concurrent writes race, and a rollback fired by a sub-agent truncates the scene you are looking at. Only the main agent touches the model. - Treat what comes back as a lead, not as truth. Verify anything surprising, or anything several features will depend on, with a direct
get_api_signaturecall. - "Can the API do what the step assumed" is itself a docs question. If an agent reports it cannot, that is a plan change: revise the step and tell the user. Do not quietly bend the step to fit the API.
Do not block on them; carry on planning while they run. If your client cannot run sub-agents, read the docs yourself before writing code. Parallelism is an optimization, never a licence to skip the lookup.
Default assumptions
Take these unless the user, the drawing, or the project says otherwise. Every one you rely on becomes a one-line // ASSUMPTION: comment next to the feature it drives.
- Units. Numbers in a file are in that file's unit. Resolution order:
unit('…')in the file, then"unit"in the nearestfluidcad.json, thenmm. Checkget_scene_summary(unit) before trusting a number. Feature defaults (fillet radius 1, chamfer 1, text size 10) are plain numbers in that unit and do not scale: pass explicit sizes in a non-mm file. For one imperial dimension in a metric part useinch()fromfluidcad/units; for an inch drawing putunit('in')right after the imports. Never multiply by 25.4 by hand. - Base plane and up. Sketch the primary outline on
"xy";+Zis up;"front"is the XZ plane. Keep the part's natural front facing FluidCAD's front. - Origin. Reference faces at the origin: a plate's bottom face on
z = 0, a revolved part's axis on Z, a symmetric part's symmetry plane through the origin. A part that will be inserted into an assembly puts its mating face or axis at the origin. - Wall thickness for an unspecified enclosure or shell: 2 to 3 mm.
- Cosmetic fillets and edge breaks where the user asked for "rounded" or "soft" edges without a number: 1 to 3 mm, applied last.
- Metric clearance holes for an unspecified bolt fit: M3 3.4, M4 4.5, M5 5.5, M6 6.6 (diameters). Model threads as plain holes at nominal diameter unless asked for thread geometry.
- Tolerances. Model nominal. A fit or tolerance is a comment, not a solid.
Clarification policy
Ask one focused question, once, batched with any others, only when the gap makes the model:
- impossible to build as described (contradictory dimensions, a feature that needs surface modeling or 3D curves),
- fit-critical (a bore, a shaft, a mating distance, a hole pattern that must match another part with no number given),
- safety-critical (load-bearing wall thickness, a guard, a pressure boundary), or
- compliance-bound (a standard the user named without the values it fixes).
Do not ask about: a default clearance hole, a cosmetic radius, a chamfer size, an origin choice, which plane to sketch on, a wall thickness for a non-structural enclosure, whether to model threads, feature order, or naming. Take the default, mark it // ASSUMPTION:, and keep building.
Autonomous fallback. When no user is available to answer (an unattended run, a benchmark, or the user said to proceed without them), the defaults are the whole procedure: proceed on assumptions, keep the build moving, and list every assumption in the final report. Do not stall.
Check the spec against itself before planning
A spec written by hand can contradict its own geometry, and the contradiction is invisible in the numbers until two features share the same space. Before planning, do the arithmetic for every feature that lives inside or next to another one, in one line each:
- A hole, slot or pocket against the wall it sits in. Its outline (centre plus radius, or slot ends plus half-width) must lie inside the material with wall left on every side, and must not break into a bore, another hole or an outside face it was not meant to reach. A bolt at
x = 22with a 5 mm drill spans 19.5 to 24.5; a 47 mm bore around the same axis reaches 23.5: that hole breaks into the bore, and no build order fixes it. - A hole or slot against the body above it. Whatever a fastener enters from must be open: nothing may stand over the outline on the insertion side. A pedestal 60 wide over slots that run from 28 to 42 buries 2 mm of each slot, and the bolt head no longer seats.
- A fastener chain. Head seat, then each thickness it passes, then engagement, then the hole floor: the numbers must add up with clearance at the tip. A 30 mm screw seated 14 mm above a split face with a 14 mm tapped hole below it bottoms out by 2 mm.
- A part inside another part's envelope. Rings, balls, pins and shafts against the width and bore they sit in; a fastener axis against every body it crosses on its way (a bolt at
y = 0through a bearing plane centred ony = 0passes through the bearing).
A number that fails this check is a spec conflict, and the clarification policy applies: it makes the model impossible as described, so ask when a user is present. Unattended, choose the fix that keeps the function (move the bolt pattern outboard of the bore, narrow the pedestal clear of the slots, shorten the screw or deepen the hole), write it as a // DEVIATION: comment on the feature, and put it at the top of the report. Never build the conflict as written and hand it in, and never wrap it in an // ASSUMPTION:: an assumption that produces two bodies in the same space is not an assumption, it is the defect.
Plan the part before writing code
The plan is the cheapest artifact in the project to change: a few paragraphs, against a model with six dependent features. Restate the requirements, pin down the dimensions that matter, then write the plan the way an experienced CAD designer would.
Write it in generic CAD terms, the vocabulary every parametric modeler shares. No FluidCAD API names, no .fluid.js syntax, no other package's menu names. "Sketch the outline on the front datum plane and extrude it through the full thickness", never extrude(40). The user can review the approach in whatever CAD tool they know; it forces feature-and-intent thinking instead of API-call thinking; and it is the artifact that drives the doc lookups and the build order.
What the plan contains
a. Design intent. What the part is, what it mounts to or does, and which dimensions are functional (bores, mating faces, hole patterns, wall thickness) versus incidental.
b. Setup: datums, origin, symmetry. Which faces and axes are the references, where the origin sits, what symmetry the part has and how the build exploits it.
c. Ordered feature steps. Numbered; for each step: what the feature is, generically; on what it is built (which datum plane or which face of which earlier feature); which dimensions drive it; why it sits at that point in the order. If you cannot say why a step comes where it does, the order is arbitrary, and an arbitrary order is the one that bites.
The default sequence: base stock (the envelope, usually the primary outline through the full thickness), then additive (bosses, pads, ribs), then subtractive (holes, pockets, slots, counterbores), then dress last (fillets, chamfers, shells, drafts).
d. Pitfalls, called against this part. Not a checklist recited back, but the traps this geometry sets: "the 3 mm corner radius must come after the corner bolt holes or it swallows them"; "the shell waits until the boss exists, or the boss comes out hollow".
How a professional thinks
- Model the way the part is made where sensible: start from stock and remove material.
- Capture design intent, not just geometry. The hole centered on the boss, the wall driven by one dimension. Geometry that merely looks right breaks the first time a dimension changes.
- Every sketch is fully constrained, always.
sketch(plane, cb)takes two arguments and every sketch is solved; coordinate literals are guesses for the solver, never the design. Pin every entity (toorigin()/xAxis()/yAxis(), a projected reference, or another entity) and dimension every size until the solver reports fully constrained. An under-constrained sketch is a defect. Keep sketches simple: complexity belongs in the feature tree, not in one giant sketch. - Reference things that move. Sketch on datum planes and on faces of earlier features, never on an offset that duplicates a dimension stated elsewhere.
- One feature, one idea. Dress features are separate features and come last; they are the most likely to change and to fail.
- Patterns over copies, mirrors over duplicate modeling. A pattern carries count and spacing as parameters.
- Model nominal geometry.
- Avoid: rounding or shelling too early; building on a face a later feature destroys; starting with detail before the envelope exists; hard-coding derived numbers; making the first sketch do too much.
Fix the origin and orientation before the first line of code
- Reference faces at the origin. Each dimension then appears in the code verbatim, with no arithmetic offsets to get wrong.
- Let symmetry pay for itself. A symmetry plane through the origin makes mirrored features free and left/right dimensions plus or minus half.
- Keep the part's natural front facing FluidCAD's front. Named screenshot views then read directly against the requirements. Rotating the part into a "nicer" orientation means re-mapping views for the rest of the session, and that is where side-of-the-part mistakes come from.
- State the choice in one line before modeling. "Origin at the center of the main bore on the bottom face, part symmetric about the YZ plane." Correcting this now is free.
Then use the plan
Show it. When a user is present, pause for them, and confirm before the first feature and before any step where you made a non-obvious choice. Under the autonomous fallback, the plan goes into the report and the build starts. Either way the plan is the script: it decides which docs to fetch and supplies the build order. If something you learn later forces a change, say so and revise it; do not silently diverge.
Writing the code
- Import every symbol from
fluidcad/core,fluidcad/filters,fluidcad/constraints,fluidcad/units.write_fileandedit_rangerefuse files with missing imports (codemissing-imports); the error'sdetails.suggestionis a paste-ready import block. - Every real dimension is a named
constat the top of the file, named after the feature it drives. The file then reads as a specification anyone can diff against the requirements. - Derive dependent dimensions instead of retyping them:
const boltCircleR = plateDia / 2 - edgeMargin;. - Prefer built-ins over hand math. A circular
repeaton thecut(), not hand-computed hole angles. - Prefer feature repeat over sketch pattern. Repeating the feature keeps each instance a first-class entity you can filter, fillet or reference later.
- Sketch on face references, not transformed planes.
sketch(e.endFaces(), ...)moves with the extrude;sketch(plane("xy", 40), ...)is a magic-number duplicate of geometry that already exists. - Keep features small and named clearly. One feature per logical operation makes filters such as
face().cylinder(5)andedge().circle(5)predictable.face().cylinder()is a full bore; a fillet or rounded corner isface().cylinderCurve(). - Comment the decisions. Anything the user resolved, every
// ASSUMPTION:, and anything you deliberately did not model (thread forms, surface finish, knurls). Silence reads as an oversight; a comment reads as a decision. - Colour every body that meets another body. Colours are model content (they survive features and export to STEP), not a viewing aid, so they are written once and kept. Give a distinct colour to every body that touches, fits into or moves against another body: each part destined for an assembly (a bare
color("steelblue")as the last statement of thepart()body paints the whole part), and each separate body inside a multi-body part (color("silver", ring),color("dimgray", balls)). Pick from a palette that stays apart in a capped section:steelblue,tomato,goldenrod,seagreen,slateblue,sienna,silver,dimgray. Two mating parts never share a colour; small parts (fasteners, balls, pins) get the warm colours so they stand out inside the big grey ones. A single-body part with no neighbours needs no colour. The existing rule stands for inspection: never add a temporarycolor()to look at a selection; that is whathighlightis for.
Build in small increments
The first goal is not a finished part. It is the smallest solid that proves the setup is right: normally the base outline extruded to the overall thickness, nothing else. Write it, confirm render.state === "rendered", screenshot, show the user. If the outline or the orientation is wrong it costs one line to fix here; six features later it costs the session.
From there, work down the plan's steps in order, one plan step (one feature, or one group of identical repeated features) per write. Say what is coming next ("base plate is done; next is the 4x 5 mm bolt pattern"). Never batch the whole part into one write: compile and build errors get harder to localize as the file grows, and a long silent stretch gives the user no chance to catch a mistake.
After writing the code
write_file and edit_range return once the render settles. Check the outcome in this order:
- Render state. If
render.stateis notrendered, the scene is not showing your change. Oncompile-errorthe previous scene is still being served: read the error (also available throughget_compile_error), fix the source, retry. Do not screenshot or inspect a broken compile; you would be looking at the old scene. - Failed features. On
build-errorthe file ran but a feature's build failed and its geometry is missing.render.objectErrorsnames each one with its message and a 1-basedsourceLocation. A fillet whose selection resolved to nothing, a shell whose offset failed and a cut that missed all land here while everything else renders. Fix them or tell the user exactly what failed. Never report the model as done on a build error.recomputeandrollback_toreport the same fields;get_scene_summaryflags the objects withhasError. - Validate the geometry. A clean render is not a geometry claim: an open body and an inside-out solid both render. Before measuring or screenshotting a new solid, run
validate;ok: truemeans every rendered solid has valid topology, a closed shell and a positive volume. A finding names the shape and the object that produced it: fix that feature first, because measurements and pictures of an unsound body are not evidence of anything. - Look. Once the render is clean,
screenshot(orscreenshot_multifor several labelled views, orscreenshot_shapefor one shape) and confirm the geometry matches intent. "It compiled" is not "it looks right". - Measure the numbers that matter.
measuretakes filter entities as well as index entities and returns a compact summary per entity (surface or curve kind, center, normal or axis, diameter, area or length), so most measurements need no image. Two parallel faces give an overall or a wall thickness; a cylindrical face gives a bore diameter; an edge gives a fillet radius or a length. Ask formeasure'simageonly when the referent is in doubt or when closing out a drawing inventory. Spot-check every dimension a later feature depends on. - Volume as a regression check only.
get_shape_properties(volume, centroid) tells you whether an edit had the effect you expected against the previous state. It cannot tell you the part is correct.
Screenshot before you build on a feature, when the feature earns it
A screenshot serves two purposes with different cadences: a verification gate for you (proof a feature did what you think before the next one depends on it: required for complex features, skippable for simple ones) and a progress checkpoint for the user (shown at natural milestones regardless; never go a long stretch without one).
Gate on a screenshot when the feature is complex, meaning its result is not fully predictable from the code:
- anything driven by a selection filter: fillet, chamfer, shell, face and edge picks. Filters over-match and under-match; you need to see which entities were caught.
- kernel-heavy features: revolve, sweep, loft, helix, wrap, draft, rib, text.
- booleans between non-trivial bodies, and anything that can quietly do less than asked: a shell that fails to offset, a cut that misses material, an offset that collapses.
- the first sketch on a new face or plane: orientation and in-plane axis errors appear here and every later feature inherits them.
- repeats and patterns: count, spacing, and especially direction sign.
- any feature whose faces or edges the next feature will reference.
Skip the gate when the feature is simple and sits on geometry you have already seen: an extrude or cut of a rect, circle, slot or polygon on a verified plane; a plain through-hole at a known position; a translate or mirror of a body you already looked at. Batch two or three of these and verify them at the next checkpoint; never batch across a plane change or in front of a complex feature.
When in doubt, screenshot. It is one tool call; unwinding three features built on a bad one is not. When the feature is inside the part (a blind hole, a counterbore, a tapped hole, a shelled wall, a bore another part will sit in), an outside view shows nothing: pass section through the feature's axis and look square on. Sections through every internal fit are mandatory before "done", and they only read when the bodies are coloured; references/verification.md lists them and says how to read one.
Two or more bodies: run interfere before you look
The moment the scene holds a second solid (a .new() body, a copy, a second part(), an inserted instance), a screenshot can no longer tell you the bodies are apart: an overlap renders as one surface hiding another. interfere reports every pair's shared volume; run it after the feature that added the body and again on the final state. Any clashes entry, and any intraPart entry you did not intend, is a defect to fix at its source (the spec conflict, the connector offset, the hole depth), not a line for the report. Then take the section through that pair to see where the overlap is.
Naming geometry: resolve first, then write the synthesized selector
The selector you write is the one the tool verified. Never edit the user's file to look at geometry (no temporary select() or color() calls): a forgotten one ships, and a viewing question is not a source edit.
- Resolve what you mean with
resolve_selection, at the scope the statement will run in and at its boundary (before, below). Give it either anexpression(your first guess at a filter) orpicks(face/edge refs fromhit_test, a highlight you looked at, or an earlier match). It returns one entry per match with its geometric summary, andcount. Zero matches is a normal result and the one that matters most: it is exactly the selection a fillet, chamfer or shell would fail on ("the selection resolved to no edges"), and a cut aimed at nothing would silently miss. More matches than you meant is the other failure; narrow the filter (or drop picks) until the count is the count you intend. - Look when the referent is in doubt. Take a
screenshotwithhighlightset to the same entities (highlights show through occluders, so bores and far-side faces read),fitTo: "highlight"to frame them,hideorfocusto clear the clutter. - Write
synthesized.sourceinto the file. That is the selector the language itself would write for exactly those matches — the same ranked, verified synthesis the UI runs on a pick. A feature accessor on a variable (e.endEdges(),c.sideFaces(2)) beats a filter that bakes a geometry constant (edge().circle(5)): it survives a dimension change, the constant does not. The source form already uses the file's variable names; checksynthesized.producers[i].bound—falsemeans the producing statement has no variable yet, so putconst <variable> =in front of it. Add whateversynthesized.importslists (select,edge,face,plane).sameAsInput: truemeans your expression already was the best form. - Fall back to a filter only when synthesis refuses.
synthesized.ok: falsenames why (geometry from a loop or helper call site, picks across part scopes, a repeat instance no accessor addresses). The matches are still valid: write a filter, resolve it again, and read the count.
synthesized.expression is the same selector in the tool's $obj["<id>"] form; resolving it again is the cheapest double-check. alternatives are verified runner-ups when the winner reads badly in context.
Boundary rule. A selection is evaluated where its statement runs, not at the tip of the model. Pass before = the scene-object index (from get_scene_summary) of the statement the selection is written before — the statement you are editing, or the one a new statement is inserted in front of. Only objects strictly before it exist then, the same world rollback_to(before - 1) renders, so the fillet's edges are resolved on the solid the fillet actually sees, and picks are addressed on that world's solids. Omit before for a statement appended at the end of the file.
Scoping rule. The evaluator sees exactly what a select(...) at that scope sees:
- scope = a scene object or a part (id from
get_scene_summary, or a part name): only that part's geometry, so a filter insidepart("base", ...)never matches a face ofpart("pillar", ...); - no scope: the whole scene, which is what a root-level
select()sees; every result names the part that owns it; - assembly files: scope by
instanceId; results carry the instance and its statement pose so they feedmeasureunchanged (nobefore, and no synthesis: selectors are written in the part file); .from(obj)inside the expression crosses parts, as it does in source.
Indices from hit_test and the scene summary still work as a fallback, but they renumber after every feature; a filter survives edits, and an accessor survives more.
When something is wrong, roll the scene back and look
When a feature comes out wrong, or a later feature fails because an earlier one was already wrong, do not re-read the source harder. Step the scene back to the state that produced the problem and look.
Find the index. get_scene_summary returns every scene object with its index, kind, parameters, 1-based source location and the shape ids it produced: the map from "the feature I care about" to both the index to roll back to and the line that produced it.
Roll back and screenshot. rollback_to(index) renders the model up to that step only. It changes render state only: the source file is untouched, the module is not re-run, shape ids stay valid. list_shapes at a rolled-back state returns only what exists up to that index, a quick check on what a feature actually produced.
Three uses that pay off repeatedly:
- Inspect the inputs to a failing feature.
resolve_selectionits filter withbefore= the feature's index (the rollback is only for looking: passbeforeand the resolver sees the same world), then roll back and screenshot withhighlight. A fillet that errors, a cut that misses or a shell that fails almost always means the face or edge it was handed was already wrong. - Bisect a part that is wrong at the end. Roll back to the middle index, look, halve again. Two or three screenshots localize the culprit faster than re-reading the file.
- Compare against a reference at an intermediate stage. Requirements and reference views often correspond to a mid-build state, before fillets, chamfers and shells cover the underlying geometry.
measurethe base dimensions there.
Restore before continuing. A rollback clears on the next full render, but do not rely on it: call recompute and confirm the full scene is back before writing more, so the user is not left staring at a truncated part.
Breakpoints are a different mechanism; reach for them only when rollback cannot help
rollback_to |
add_breakpoint |
|
|---|---|---|
| What it does | Re-renders an already-built scene truncated at a feature index | Inserts a real breakpoint() statement into the source and aborts execution there on the next render |
| Touches the source file | No | Yes, with the weight of any other write |
| Re-runs the module | No: fast, shape ids stay valid | Yes, and execution stops: nothing after that line is built |
| Synchronous | Yes | No: returns success as soon as the request is sent |
| Needs an editor attached | No | Yes: routed through the VSCode/Neovim extension. On a standalone fluidcad serve it returns success and does nothing |
| Clears itself | Yes, on the next full render | No: the statement stays until clear_breakpoints removes it |
Default to rollback. Reach for a breakpoint only when the state you need never becomes a scene object: the module throws partway through, or the geometry lives inside a loop, a helper or a sketch body and fails before anything reaches the scene.
When you do use one: say so before doing it and strip it with clear_breakpoints the moment you are done. Do not trust the line convention: add_breakpoint documents line as zero-based while every sourceLocation the server returns is 1-based, so pass the line, then read_file and confirm where the breakpoint() statement actually landed before drawing conclusions from the partial scene. Because the call is fire-and-forget, verify the result rather than assuming it took effect.
Handling unsaved-buffer conflicts
write_file and edit_range refuse to clobber a buffer the editor has unsaved changes for (code dirty-buffer). Surface the conflicting paths to the user and ask before retrying with force: true. Overwriting their in-progress work without checking is a serious failure.
Known limitations
FluidCAD does not currently support 3D curves (work around by sketching on several planes and combining), or surface modeling and sheet metal. If the request fundamentally needs them, say so up front rather than faking it with solids.
Progressive references
Load only what the task needs, from this skill's references/ folder:
references/traps.md: read before fillet, chamfer, shell, cut, repeat,plane()offsets, sketching on a face, or a breakpoint. FluidCAD-specific silent failures with their signatures and fixes.references/repair-loop.md: read the momentrender.stateis notrendered. Failure classes keyed by the actualcompileErrorandobjectErrorsmessages, with the smallest fix and what to rerun.references/verification.md: read before declaring any feature or part done. Screenshot skip list, the visual-concern-to-deterministic-check table, the mandatoryinterfereand section gates and how to read a section, what never to claim, the final report template.references/modifying.md: read when the task starts from an existing file rather than a blank one.references/sketching.md: read before the first sketch, or when a sketch solves somewhere you did not draw it.references/handoff.md: read when the user wants an STL, a STEP, a package, or asks "how do I use this".
Assemblies (parts, inserts, mates, connectors) are covered by the separate FluidCAD-assembly skill; modeling from a drawing by FluidCAD-from-drawing.
Quick reference: the loop
- Read the docs for the step (
search_docs/read_doc/get_api_signature/get_type_definition), in parallel sub-agents where possible. Sub-agents read; they never build. - Agree on the step with the user when one is present; otherwise proceed on stated assumptions. Spec conflicts (a hole that breaks into a bore, a slot under a wall, a fastener that bottoms out) are found and settled before the first write.
- Write the code with all imports, dimensions as named consts, dependents derived, and a colour on every body that meets another body.
- Check
render.state; fix compile errors and everyobjectErrorsentry before going further. validateevery new solid;interfereas soon as there are two; then screenshot when the feature earns it (asectionthrough anything internal), andmeasurethe numbers a later feature depends on.- Before a filter-driven feature,
resolve_selectionyour expression or picks at the right scope and boundary,highlightit if in doubt, then writesynthesized.source. - When something looks wrong,
rollback_tothe feature before it and look;recomputeto restore before writing more. - Move on to the next feature.
Version History
-
6ea7272
Current 2026-09-22 06:41
新增sketch完全约束规则说明;更新selection合成逻辑;优化interference工具与选择器处理;修正YAML格式问题。
- 07c07a7 2026-08-13 16:07
- cf8ea9a 2026-07-31 13:31
- 2e6b33d 2026-07-05 20:07


