REFERENCE / 04
Components
A component is a named, parameterized, closed geometry unit. Define once, instantiate anywhere, override knobs at the call site. model and part stay valid forever; components add reuse on top without changing them.
define-component
(define-component knuckle
((number pin_d 8 :label "Pin diameter" :min 4 :max 12 :step 0.5)
(number clearance 0.3))
(difference
(cylinder (* 2 pin_d) 10 96)
(cylinder (+ pin_d clearance) 12 96)))- positional 1: component name symbol
- positional 2: signature list; entries use the same grammar as
params
entries (kind, key, optional default, keyword metadata)
- final positional: one geometry expression
- optional
(verify ...)clauses may sit alongside the geometry expression - declaration is top-level, before
(model ...)
Instantiation
(part hinge_a (knuckle :pin_d 6)) ; override pin_d, clearance defaults
(part hinge_b (knuckle)) ; all defaults apply- arguments are keywords only:
(name :key value ...) - omitted keys take their signature defaults
- a signature entry without a default is required at every call site
- unknown keyword or missing required key fails compile with the component
name and its signature listed
- components instantiate other components; cycles are rejected and nesting
is capped at depth 32
Closedness
A component body sees its signature keys plus bindings made inside the body (let, let*, lambda parameters, repeat indices, build shapes) and nothing else. Referencing a model param or outer binding is a compile error naming the variable and the component. Closedness is what makes a component copy-inlineable: paste the define-component into any model and it works.
Verify travel
verify clauses inside a component expand once per instantiation, with the tag namespaced by the instantiating part key:
(define-component pin ((number d 2))
(verify (tag pin_ok) (metric min_wall_thickness "body") (expect (>= value 1)))
(cylinder d 10 48))
(part left (pin :d 3)) ; verify tag becomes left/pin_okA pasted component therefore carries its own checks — reuse includes proof.
Component Library Workflow (MCP)
Agents lift proven parts into the shared library and reuse them by source:
1. component_extract — pass the model source and a partKey. Referenced model params become the signature with metadata preserved; scalar outer let/let* bindings become plain defaults; non-scalar free references are reported as blockers. Set save: true to store the component. 2. component_search — compact headers only (name, one-liner, param keys, tags). Bodies are never returned by search. 3. component_get — full copy-inline define-component source for one component by name. Paste it into the model and instantiate it.
Extraction is copy-inline only: the returned source is self-contained and no registry reference is created implicitly.
Live package references
Use a live reference when the authored model must retain an installed package coordinate instead of vendoring source:
(import-component
"bike.bottle-holder-kit"
:version "1.2.0"
:component "bottle-cage"
:as cage)
(model
(part holder
(cage :diameter 74)))Package id, version, component id, and alias are mandatory literal values. Resolution is exact. No semver ranges, latest, network fallback, or transitive package lookup occurs.
Copy-inline and live reference are separate modes:
component_getis vendor mode: paste closed source; no package dependency
or dependency lock exists afterward.
import-componentis live mode: the committed model version owns a
canonical exact lock containing package coordinates and payload digests.
- preview, render, export, reopen, and historical rerender read the appended
lock and never update it.
- installing a newer package changes nothing until an explicit upgrade
previews and appends a new model version. The old version keeps its old lock.
Payloads live once in the application-global content-addressed store. Models do not receive node_modules-style dependency trees. Uninstall removes package discovery; committed locks continue resolving their immutable payload digests. Garbage collection removes a payload only after installed coordinates, committed versions, and in-flight operations stop retaining it.
Filesystem projects mirror the canonical lock as ecky.lock.edn. Normal export references the global store. Portable export vendors locked payloads by digest; portable import verifies every digest before publishing anything.
STEP-backed live components preserve analytic BRep provenance and import through native Direct OCCT. This path never calls FreeCAD, converts through STL, invokes solidify, repairs geometry, or implicitly fuses multiple roots. STL remains the separate import-stl → solidify mesh bridge.