Files
create/docs/INTEGRATION_PLAN.md
forbes 5a0be2804d
All checks were successful
Build and Test / build (pull_request) Successful in 29m17s
docs(sdk): add KCSDK API reference and addon developer guide
- docs/src/reference/kcsdk-python.md: full kcsdk Python API reference
- docs/src/development/writing-an-addon.md: step-by-step addon guide
- docs/INTEGRATION_PLAN.md: add Phase 7 KCSDK section
- docs/ARCHITECTURE.md: add src/Gui/SDK/ to source layout
- docs/src/SUMMARY.md: add new pages to mdBook navigation
2026-02-28 14:53:51 -06:00

17 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: Silo has been migrated to use the SDK (#250) — it declares <dependency>sdk</dependency> and uses kindred_sdk for overlay registration and theme tokens. ztools has not yet been migrated: its package.xml lacks <kindred> metadata and its InitGui.py does not import from kindred_sdk. See KNOWN_ISSUES.md next step #9.

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.


Phase 7: KCSDK — C++-backed SDK module -- IN PROGRESS

Goal: Replace the pure-Python SDK wrappers with a C++ shared library (libKCSDK.so) and pybind11 bindings (kcsdk.so). This gives addons a stable, typed API with proper GIL safety and enables future C++ addon development without Python.

Architecture:

Python Addons (silo, future addons, ...)
       |
kindred_sdk  (mods/sdk/)              <- convenience layer (try kcsdk, fallback FreeCADGui)
       |
kcsdk.so     (pybind11 module)        <- C++ API bindings
       |
KCSDK        (C++ shared library)     <- SDKRegistry + provider interfaces
       |
FreeCADGui   (EditingContextResolver, DockWindowManager, OriginManager, ...)

Sub-phases:

# Issue Status Description
1 #350 DONE Scaffold KCSDK library + kcsdk pybind11 module
2 #351 DONE Migrate editing context API to kcsdk
3 #352 DONE Panel provider system (IPanelProvider)
4 #353 C++ theme engine
5 #354 Toolbar provider system (IToolbarProvider)
6 #355 Menu and action system
7 #356 Status bar provider + origin migration
8 #357 Deprecation cleanup + SDK v1.0.0

Key files:

  • src/Gui/SDK/ — C++ library (KCSDKGlobal.h, Types.h, SDKRegistry, IPanelProvider, WidgetBridge)
  • src/Gui/SDK/bindings/ — pybind11 module (kcsdk_py.cpp, PyIPanelProvider, PyProviderHolder)
  • mods/sdk/kindred_sdk/ — Python wrappers with kcsdk/legacy fallback

Design decisions:

  • No Qt in public C++ APITypes.h uses std::string, std::vector, std::function. Qt conversion happens internally in SDKRegistry.cpp.
  • GIL-safe Python callables — Python callbacks stored via std::make_shared<py::object> with py::gil_scoped_acquire before every invocation.
  • PySide widget bridgingWidgetBridge::toQWidget() converts PySide QWidget objects to C++ QWidget* via Gui::PythonWrapper (Shiboken).
  • Provider pattern — Interfaces like IPanelProvider enable addons to register factories. The registry calls create_widget() once and manages the lifecycle through DockWindowManager.

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.