Files
create/docs/INTEGRATION_PLAN.md
forbes-0023 252e2c3b3e
Some checks failed
Build and Test / build (pull_request) Failing after 2m1s
docs: update architecture docs for addon-first model (#255)
ARCHITECTURE.md:
- Replace exec()-based bootstrap flow with manifest-driven loader diagram
- Add addon lifecycle section (scan → parse → validate → resolve → load → register)
- Add SDK and C++ scaffold to source layout
- Document load order: sdk (0) → ztools (50) → silo (60)

INTEGRATION_PLAN.md:
- Add Layer 4 (Addon SDK) between bootstrap and addons (now 5 layers)
- Update Layer 3: now hosts both Python loader AND C++ scaffold
- Add Phase 1.5 (SDK) and Phase 1.75 (C++ scaffold) as DONE
- Update Phase 4 (theme): colors centralized in SDK YAML palette
- Update Phase 6 (build): now DONE with CMake install rules for all addons
- Add design decisions #7 (SDK as adaptation layer) and #8 (manifest-driven loading)

README.md:
- Update addon integration section: manifest-driven loading, SDK wrappers
- Add mods/sdk/ to project structure tree
- Update Create module description to mention C++ scaffold

Closes #255.
2026-02-17 12:38:18 -06:00

15 KiB

Integration Plan

Strategy for integrating ztools and Silo as built-in addons while maintaining clear boundaries with FreeCAD core.

Goals

  1. Native feel -- ztools and Silo behave as first-class citizens, not bolted-on addons
  2. Clean boundaries -- Clear separation between FreeCAD core, Kindred extensions, and addon code
  3. Minimal core modifications -- Preserve FreeCAD's container models (Part, Body, Assembly)
  4. Maintainability -- Easy to pull upstream FreeCAD changes without merge conflicts
  5. Extensibility -- Architecture supports future Kindred-specific features

Architecture layers

┌─────────────────────────────────────────────────────────────┐
│                   Kindred Create Application                 │
├─────────────────────────────────────────────────────────────┤
│  Layer 5: Kindred Addons (mods/)                            │
│  ┌──────────────────┐  ┌──────────────────┐                 │
│  │     ztools        │  │      Silo        │                 │
│  │  Datum Creator    │  │  Open/Save/Commit│                 │
│  │  Enhanced Pocket  │  │  Part numbering  │                 │
│  │  Assembly Patterns│  │  Revision control│                 │
│  │  Spreadsheet fmt  │  │  BOM management  │                 │
│  └──────────────────┘  └──────────────────┘                 │
├─────────────────────────────────────────────────────────────┤
│  Layer 4: Kindred Addon SDK (mods/sdk/)                     │
│  ┌─────────────────────────────────────────────────────────┐│
│  │  Stable API contract: context, theme, origin, dock      ││
│  │  Isolates addons from FreeCADGui.* platform internals   ││
│  └─────────────────────────────────────────────────────────┘│
├─────────────────────────────────────────────────────────────┤
│  Layer 3: Kindred Create Module (src/Mod/Create/)           │
│  ┌─────────────────────────────────────────────────────────┐│
│  │  Python: manifest-driven addon loader, Silo integration ││
│  │  C++: CreateApp / CreateGui libraries (feature scaffold)││
│  └─────────────────────────────────────────────────────────┘│
├─────────────────────────────────────────────────────────────┤
│  Layer 2: FreeCAD Python API                                │
│  ┌─────────────────────────────────────────────────────────┐│
│  │  FreeCAD, FreeCADGui, Part, PartDesign, Sketcher,       ││
│  │  Assembly, WorkbenchManipulator                         ││
│  └─────────────────────────────────────────────────────────┘│
├─────────────────────────────────────────────────────────────┤
│  Layer 1: FreeCAD Core (C++)                                │
│  ┌─────────────────────────────────────────────────────────┐│
│  │  App::Document, Part::Feature, PartDesign::Body, etc.   ││
│  └─────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘

Boundary definitions

Layer 1: FreeCAD Core -- do not modify

FreeCAD's fundamental data structures: PartDesign::Body, PartDesign::Pocket, Part::Feature, App::Document, Sketcher::SketchObject. Modifying these creates merge conflicts with upstream and risks breaking FCStd file compatibility.

Layer 2: FreeCAD Python API -- use as-is

The Python API provides everything needed for feature creation, command registration, and geometry access. ZTools and Silo operate entirely through this layer. Stable FreeCAD APIs (Gui.addCommand(), Gui.addWorkbench(), Gui.addWorkbenchManipulator()) are called directly — they do not need SDK wrappers.

Layer 3: Kindred Create Module -- src/Mod/Create/

The Create module serves two roles:

Python bootstrap (Init.py, InitGui.py, addon_loader.py):

  • Scans mods/ for package.xml manifests with <kindred> extensions
  • Validates version compatibility, resolves dependencies via topological sort
  • Loads addons in priority order (sdk → ztools → silo)
  • Populates FreeCAD.KindredAddons registry for runtime introspection
  • Sets up deferred Silo dock panels, origin registration, and update checker

C++ module scaffold (App/, Gui/, CreateGlobal.h):

  • CreateApp.so and CreateGui.so shared libraries
  • Currently scaffold-only (no features). Will host Create::FlipPocket and other C++ features that need to compile with the application rather than live in mods/.
  • Follows the Assembly module pattern (PyMOD_INIT_FUNC, Py::ExtensionModule)

Layer 4: Kindred Addon SDK -- mods/sdk/

The SDK is a pure-Python package that provides stable wrappers around Kindred-specific platform APIs. Addons import from kindred_sdk instead of calling FreeCADGui.* platform internals directly. This creates a single adaptation point during upstream rebases.

SDK modules:

  • context — editing context registration (register_context, register_overlay, inject_commands, etc.)
  • theme — YAML-driven palette system (get_theme_tokens, load_palette, Palette)
  • origin — FileOrigin registration (register_origin, unregister_origin)
  • dock — deferred dock panel helper (register_dock_panel)
  • compat — version detection (create_version, freecad_version)

The SDK is loaded first (priority 0) and has no dependencies.

Layer 5: Kindred Addons -- mods/

Pure Python addons with package.xml manifests. Self-contained with Init.py, InitGui.py, and <kindred> metadata. Developed and versioned independently as git submodules. Must declare <dependency>sdk</dependency> to use SDK APIs.


Phase status

Phase 1: Addon auto-loading -- DONE

Implementation: src/Mod/Create/addon_loader.py implements manifest-driven loading with dependency resolution. Replaces the original exec()-based approach. Each addon provides a package.xml with <kindred> extensions specifying version bounds, load priority, and dependencies.

Default workbench: PartDesignWorkbench (set in PreferencePacks/KindredCreate/KindredCreate.cfg). ZTools is no longer a workbench — its commands are injected into native workbench toolbars via the EditingContextResolver and WorkbenchManipulator systems.

Registry: FreeCAD.KindredAddons provides runtime introspection — .loaded() returns addon names and states, .get(name) returns manifest data, .contexts() lists registered editing contexts.

Phase 1.5: Addon SDK -- DONE

Goal: Provide a stable API contract between the Create platform and addons, isolating addons from FreeCADGui.* platform internals that may change during upstream rebases.

Implementation: mods/sdk/kindred_sdk/ package with wrappers for editing contexts, theme tokens, FileOrigin registration, and dock panel creation. YAML-driven palette system (palettes/catppuccin-mocha.yaml) replaces hardcoded color dicts that were duplicated across 5+ locations.

Migration: Both ztools and Silo have been migrated to use the SDK (#250). No addon code calls FreeCADGui.registerEditingOverlay(), FreeCADGui.addOrigin(), or defines hardcoded MOCHA dicts directly.

Phase 1.75: C++ module scaffold -- DONE

Goal: Establish src/Mod/Create/App/ and src/Mod/Create/Gui/ so Kindred-specific C++ features have a proper build target.

Implementation: CreateApp.so and CreateGui.so shared libraries following the Assembly module pattern. Currently scaffold-only — no features registered. The existing Python bootstrap continues working alongside the C++ module.

Phase 2: Enhanced Pocket as C++ feature -- NOT STARTED

Goal: Replace the Python boolean-operation workaround in ZTools_EnhancedPocket with a proper Create::FlipPocket C++ feature inheriting from PartDesign::ProfileBased.

Rationale: The current Python implementation creates a standard Pocket then applies a boolean Common. A native feature would integrate properly with the feature tree, support undo/redo correctly, and perform better on complex geometry.

Scope:

  • src/Mod/Create/App/FeatureFlipPocket.cpp -- Feature implementation
  • src/Mod/Create/Gui/TaskFlipPocket.cpp -- Task panel
  • src/Mod/Create/Gui/ViewProviderFlipPocket.cpp -- View provider
  • Update ZTools_EnhancedPocket to create Create::FlipPocket instead of the workaround

Decision: Deferred. The Python approach is functional for current needs. Revisit when performance or feature-tree integration becomes a problem.

Phase 3: Datum C++ helpers -- NOT STARTED (SUPERSEDED)

Original goal: Create C++ geometry helper functions for datum calculations.

Current state: The Python implementation now uses FreeCAD's built-in Part::AttachExtension for automatic parametric updates. Each datum type maps to a native MapMode (FlatFace, ThreePointsPlane, NormalToEdge, etc.) with appropriate AttachmentSupport and AttachmentOffset. This eliminates the need for custom geometry calculations.

Decision: Superseded by the AttachExtension approach. Only tangent_to_cylinder still uses manual placement (requires a vertex reference not currently collected by the UI).

Phase 4: Theme system -- DONE

Goal: Theme applies consistently at startup regardless of active workbench.

Current state: The Catppuccin Mocha theme is set as the default via the KindredCreate preference pack. The canonical QSS lives in src/Gui/Stylesheets/KindredCreate.qss. The PreferencePacks copy is generated at build time via configure_file() in src/Gui/PreferencePacks/CMakeLists.txt.

Theme colors are now centralized in the SDK's YAML palette (mods/sdk/kindred_sdk/palettes/catppuccin-mocha.yaml). Addons use kindred_sdk.theme.get_theme_tokens() instead of hardcoding color dicts. The SDK provides a Palette class for programmatic access to colors and semantic roles.

Phase 5: Silo deep integration -- DONE

Goal: Silo commands available globally, not just in the Silo workbench.

Implementation: The unified origin system (FileOrigin, OriginManager, OriginSelectorWidget) in src/Gui/ delegates all file operations (New/Open/Save) to the selected origin. Standard commands (Std_New, Std_Open, Std_Save) and origin commands (Origin_Commit, Origin_Pull, Origin_Push, Origin_Info, Origin_BOM) are built into the File toolbar and menu. The Silo workbench no longer has its own toolbar — it only provides a menu with admin/management commands.

Dock panels: Database Auth (2000ms), Database Activity (4000ms), and Start Panel panels are created via deferred QTimers using kindred_sdk.register_dock_panel(). The Activity panel displays real-time server events via SSE with automatic reconnection. The Start Panel provides an in-viewport landing page with recent files and Silo integration.

Phase 6: Build system integration -- DONE

Goal: CMake install rules for mods/ submodules so packages include ztools, Silo, and SDK automatically.

Implementation: src/Mod/Create/CMakeLists.txt includes install rules for all addons (mods/ztools, mods/silo, mods/sdk) and the C++ module scaffold (App/, Gui/). Build-time code generation: version.py.inversion.py via configure_file().

CI/CD status: Release workflows (.gitea/workflows/release.yml) build for Linux (AppImage + .deb), macOS (DMG for Intel + Apple Silicon), and Windows (.exe NSIS installer + .7z archive). Builds run on public runners in dockerized mode. Releases are triggered by v* tags. See docs/CI_CD.md for details.


Design decisions

  1. Create:: namespace prefix. All Kindred Create C++ features use this prefix to distinguish them from FreeCAD core.

  2. No upstream contribution. Kindred Create is a standalone product. This allows divergent design decisions without upstream coordination. Category 3 bug fixes (see UPSTREAM.md) may be upstreamed to reduce patch burden.

  3. Silo server distributed separately. Users deploy the Silo server independently. Setup instructions live in mods/silo/README.md.

  4. Version synchronization via submodule pins. ztools and Silo versions are pinned git submodule commits. Updates are deliberate:

    cd mods/ztools && git pull origin main && cd ../..
    git add mods/ztools && git commit -m "Update ztools submodule"
    
  5. Python-first approach. C++ extensions are deferred until Python cannot achieve the requirement. The AttachExtension approach for datums validated this strategy.

  6. Graceful degradation. The addon loader skips addons that fail validation or loading. Each addon load is wrapped in try/except with console logging. The SDK, ztools, and Silo can all be absent without breaking the bootstrap.

  7. SDK as adaptation layer. Addons call kindred_sdk.* instead of FreeCADGui.* platform internals. This creates a single point of adaptation during upstream rebases — update the SDK wrappers, not every addon.

  8. Manifest-driven loading. Addons declare version bounds, dependencies, and load priority in package.xml <kindred> extensions. This replaces hardcoded load lists and enables third-party addons in the future.