Skip to main content
This page is agent-facing operating guidance for reliable Parashell automation. Treat it as a practice layer over the API references.

Document lifecycle

  • Resolve the active document explicitly. If a task may run in an empty process, create a document with FreeCAD.newDocument(...).
  • Close temporary documents with FreeCAD.closeDocument(doc.Name) or FreeCAD.closeDocument("Name") in cleanup paths.
  • Use internal Name for programmatic lookup and durable object references. Use Label for human-facing naming and expression label references only when the expression syntax explicitly requires it.
  • Use doc.getObject(name_or_id) when the exact internal name or numeric id is known.
  • Use doc.findObjects(Type="...", Name="...", Label="...") for filtered discovery.
  • Use doc.getObjectsByLabel(label) only when label-based ambiguity is acceptable or expected.
  • Use doc.supportedTypes() before constructing optional or workbench-dependent TypeIds. Part::Feature creation should be guarded this way and falls back to Part.show(shape, name) when needed.
  • Prefer doc.Objects, doc.RootObjects, and doc.TopologicalSortedObjects for inventory or dependency-sensitive traversal.

Transactions

  • Wrap coherent document mutation in a transaction:
  • Use transaction labels that identify the modeling intent, not implementation trivia.
  • Treat document transactions as potentially application-scoped. The Document.pyi stub documents openTransaction(name) as routing through FreeCAD.setActiveTransaction(name), and multi-document changes can share one internal transaction id.
  • Commit only after all properties and links in that logical edit are assigned.
  • Abort on exceptions before retrying with a different strategy.
  • Use doc.hasPendingTransaction when recovery logic needs to know whether abort/commit is valid.
  • doc.undo(), doc.redo(), doc.clearUndos(), and doc.clearDocument() exist, but agents should not use them as primary modeling operations. Use them for explicit rollback workflows or tests.
  • Use FreeCAD.getActiveTransaction() and FreeCAD.closeActiveTransaction(abort=False, id=0) when coordinating application-level transaction state directly.

Recompute discipline

  • Recompute after creating geometry, setting expressions, changing spreadsheet cells, adding TechDraw views, or changing parameter objects.
  • doc.recompute() returns an object count. Capture it when the task needs to know whether a mutation actually propagated.
  • doc.recompute([obj1, obj2]) is supported. Use targeted recompute for parameter propagation tests or narrow dependency updates, then validate downstream state.
  • doc.recompute(objects, force, checkCycle) accepts force and checkCycle booleans at the binding layer. Use cycle checking when generating or modifying expression graphs.
  • Use object state as a dependency signal. Check "Touched" in obj.State and "Up-to-date" in dimension.State when validating state.
  • obj.recompute(recursive=False) recomputes a feature and returns a boolean. Prefer document recompute for normal modeling because document dependencies are broader.
  • obj.isValid() is available for object validity checks; shape-specific validation still requires shape inspection.

Expressions

  • Use obj.setExpression(path, expr) with expr as a string.
  • Use obj.setExpression(path, None) or obj.clearExpression(path) to remove an expression. Do not overwrite with an empty string unless the target API explicitly documents that behavior.
  • Use obj.getExpression(path) when checking current bindings.
  • Expression changes create dependency edges. Validate expected propagation by recomputing and checking touched state or driven property values.
  • Use hiddenref(...) only when the dependency is intentionally hidden from normal object link tracking. hiddenref(VarSet.Length) removes ordinary InList, OutList, and property edge visibility while still allowing expression evaluation. This is a specialized dependency tool, not a default reference form.
  • Use setPropertyStatus(name, "Output") for computed output properties and setPropertyStatus(name, ["Input"]) for input properties that should participate in fine-grained dependency behavior.

Parameter objects

  • Use App::VarSet for compact named parameters when a full spreadsheet is unnecessary.
  • Use explicit property types such as App::PropertyLength, App::PropertyInteger, App::PropertyBool, App::PropertyString, and App::PropertyEnumeration.
  • Put parameter properties in a stable group such as "Params" so later introspection can distinguish design inputs from incidental object properties.
  • Use FreeCAD.Units.Quantity("32.0 mm") or string quantities like "20 mm" for dimensional values. Do not rely on unitless floats for dimensions unless the target property semantics are known.

Property introspection

  • Query obj.PropertiesList before assigning uncommon properties.
  • Use obj.getPropertyByName(name, checkOwner) when direct attribute access could cross a link boundary. checkOwner=1 requires local ownership; checkOwner=2 returns owner plus value.
  • Query obj.getTypeIdOfProperty(name) before coercing values for dynamic or unfamiliar properties.
  • Query obj.getGroupOfProperty(name) to distinguish design inputs, outputs, and implementation groups.
  • Query obj.getDocumentationOfProperty(name) when an agent needs the property intent.
  • Respect property status. The binding exposes status concepts including Output, Input, NoRecompute, NoPersist, ReadOnly, and Hidden.
  • Use negative status values or text prefixed with - only when intentionally clearing property status.
  • For Python feature objects, add properties before assigning values, set status before depending on the property, and implement execute(obj) to update shape/output properties.

Sketch and PartDesign

  • For PartDesign profiles, create a PartDesign::Body, then create the sketch with body.newObject("Sketcher::SketchObject", "Sketch").
  • Attach sketches to origin planes when constructing base profiles:
  • Use Part.LineSegment(FreeCAD.Vector(...), FreeCAD.Vector(...)) and other Part geometry constructors for sketch geometry.
  • Batch-add geometry and constraints where possible:
  • Set sketch dimensions through constraints and datum values, not by leaving underconstrained raw geometry:
  • Use sketch.setGeometryIds(...) when the model expects stable geometry ids.
  • For pads, assign pad.Profile = sketch, set length with an explicit unit, and set pad.ReferenceAxis when the source pattern requires an axis.
  • Recompute the document after constructing the profile before measuring body.Shape or downstream feature output.
  • Validate parametric sketch updates by changing the driving parameter, recomputing, and checking dimensions through body.Shape.BoundBox.

Shape validation

  • Validate created or modified solids by checking the object shape, not just object existence.
  • Use obj.Shape.BoundBox for dimensional assertions and screen-space selection setup.
  • Use shape validity/null checks when available for the shape type. Pair them with recompute and measurable shape assertions.
  • Use Shape.Volume, BoundBox.XLength, BoundBox.YLength, and BoundBox.ZLength for coarse geometry sanity checks after recompute.
  • For boolean or generated Part shapes, assign the resulting shape to a Part::Feature only after confirming the target TypeId is available.
  • Do not treat a successful addObject call as proof that recompute produced valid geometry.

Spreadsheet practices

  • Create sheets with doc.addObject("Spreadsheet::Sheet", "Spreadsheet").
  • Set cells with sheet.set(cell, value_or_formula), then recompute before reading calculated attributes or dependent geometry.
  • Use aliases for stable parametric references:
  • Alias names must be unique, must not be cell addresses, and must not collide with units or reserved words. Duplicate and invalid aliases are expected to fail.
  • Clear an alias with sheet.setAlias("A1", ""); sheet.getAlias("A1") should then return None.
  • Renaming an alias updates formulas and expression-engine bindings. After rename, inspect sheet.getContents(cell) or obj.ExpressionEngine if correctness depends on the rewritten reference.
  • Use label-qualified references such as <<Spreadsheet>>.Length when the expression needs object label semantics. If the label changes, verify the expression engine rewrites to the new label form.
  • Insert/remove rows and columns can move aliases and formulas. Recompute and inspect aliases after structural edits.
  • Wrap alias creation in transactions when undo/reuse behavior matters.
  • Cross-document expressions require saved documents. The tests save, reopen, then validate cross-document links. Do not assume unsaved document names are durable references.
  • Spreadsheet formulas support units, ranges, aggregate functions, conditionals, vector/matrix/rotation/placement constructors, and aliases. Validate units because range aggregation with mixed units returns error strings.
  • Use .cells.Bind... and .cells.BindHiddenRef... expression paths only when binding spreadsheet cell regions intentionally. Clear with setExpression(path, None).

Draft API

  • The Draft public programming interface is designed so its creation/manipulation functions are usable without requiring the graphical user interface.
  • Use Draft for 2D construction objects, cleanup, transforms, wires, arrays, SVG/DXF extraction, and object type utilities.
  • Prefer public constructors and functions exported by Draft.py, including make_line, make_wire, make_circle, make_rectangle, make_polygon, array, move, rotate, scale, offset, mirror, upgrade, downgrade, join_wires, split, fuse, cut, extrude, heal, draftify, shapify, get_type, get_objects_of_type, get_svg, and get_dxf.
  • Guard GUI-dependent helpers with FreeCAD.GuiUp. Selection, style, active view, and viewprovider helpers are not headless-safe by default.
  • Recompute after Draft object creation or transform operations before measuring geometry or exporting downstream artifacts.

BIM and architectural API

  • Guard active-document assumptions. Source constructors abort or return when no active document exists for active-document-only APIs.
  • Creation functions typically return the created object. Capture that return value and continue mutating that object directly.
  • FeaturePython patterns create an object, assign a proxy, optionally assign a viewprovider only when FreeCAD.GuiUp, set domain properties, recompute, and return the object.
  • Normalize single-object/list inputs before adding them to container objects. makeAxisSystem coerces one axis to a list; building-part helpers accept both one object and a sequence.
  • Set domain metadata explicitly, for example IfcType and CompositionType, after object creation.
  • Do not assume BIM object creation recomputes in every helper. Some helpers recompute immediately; others return after assigning properties. Recompute before validation.

TechDraw

  • Create a page and template before views:
  • Add views to the page with page.addView(view) before final validation.
  • Use list form for sources where the API expects it:
  • For Draft views, use TechDraw::DrawViewDraft, set Source, set Direction, add to the page, then recompute.
  • For dimensions, create TechDraw::DrawViewDimension, add it to the page, set Type, set References2D, then recompute.
  • Verify drawing state with "Up-to-date" in dimension.State or equivalent view/page state checks before reporting a drawing as current.
  • Rendering or page inspection should happen after recompute, not immediately after object creation.

GUI boundaries

  • Always check FreeCAD.GuiUp before importing GUI modules, assigning viewproviders, updating views, or using selection/viewport APIs.
  • Headless agent snippets should avoid GUI-only state. If the task needs rendered confirmation through GUI APIs, only run that path after FreeCAD.GuiUp is true.
  • When GUI selection tests create geometry, they recompute, refresh the view, and only then inspect projected bounds. Follow the same order for viewport-dependent workflows.

Python feature objects

  • Use Part::FeaturePython or App::FeaturePython when the object needs a Python proxy.
  • Proxy setup pattern:
  • Keep output properties marked as output so expression dependencies can distinguish generated values from design inputs.
  • If onChanged eagerly recomputes an output, still validate via document recompute because other dependent objects may not update until the document graph runs.

File and cross-document workflows

  • Use saveAs(...), close/reopen, then validate when testing persistence of expressions, spreadsheet formulas, strings, or cross-document links.
  • Do not depend on temporary unsaved document identity for cross-file references.
  • When an expression includes another document, verify after reopening both documents because persistence behavior is part of the contract being tested.

Agent direct-use policy

  • Use the FreeCAD-compatible Python surface directly for compiled-binding introspection, uncommon TypeIds, dynamic properties, expression graph inspection, and workbench APIs.
  • Before assigning an unfamiliar property, introspect PropertiesList and metadata.
  • Before using an unfamiliar TypeId, check doc.supportedTypes().
  • After any mutation path, recompute and validate the exact changed objects.