- 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
17 KiB
Integration Plan
Strategy for integrating ztools and Silo as built-in addons while maintaining clear boundaries with FreeCAD core.
Goals
- Native feel -- ztools and Silo behave as first-class citizens, not bolted-on addons
- Clean boundaries -- Clear separation between FreeCAD core, Kindred extensions, and addon code
- Minimal core modifications -- Preserve FreeCAD's container models (Part, Body, Assembly)
- Maintainability -- Easy to pull upstream FreeCAD changes without merge conflicts
- 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/forpackage.xmlmanifests with<kindred>extensions - Validates version compatibility, resolves dependencies via topological sort
- Loads addons in priority order (sdk → ztools → silo)
- Populates
FreeCAD.KindredAddonsregistry for runtime introspection - Sets up deferred Silo dock panels, origin registration, and update checker
C++ module scaffold (App/, Gui/, CreateGlobal.h):
CreateApp.soandCreateGui.soshared libraries- Currently scaffold-only (no features). Will host
Create::FlipPocketand other C++ features that need to compile with the application rather than live inmods/. - 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 implementationsrc/Mod/Create/Gui/TaskFlipPocket.cpp-- Task panelsrc/Mod/Create/Gui/ViewProviderFlipPocket.cpp-- View provider- Update
ZTools_EnhancedPocketto createCreate::FlipPocketinstead 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.in → version.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++ API —
Types.husesstd::string,std::vector,std::function. Qt conversion happens internally inSDKRegistry.cpp. - GIL-safe Python callables — Python callbacks stored via
std::make_shared<py::object>withpy::gil_scoped_acquirebefore every invocation. - PySide widget bridging —
WidgetBridge::toQWidget()converts PySide QWidget objects to C++QWidget*viaGui::PythonWrapper(Shiboken). - Provider pattern — Interfaces like
IPanelProviderenable addons to register factories. The registry callscreate_widget()once and manages the lifecycle throughDockWindowManager.
Design decisions
-
Create::namespace prefix. All Kindred Create C++ features use this prefix to distinguish them from FreeCAD core. -
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. -
Silo server distributed separately. Users deploy the Silo server independently. Setup instructions live in
mods/silo/README.md. -
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" -
Python-first approach. C++ extensions are deferred until Python cannot achieve the requirement. The AttachExtension approach for datums validated this strategy.
-
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.
-
SDK as adaptation layer. Addons call
kindred_sdk.*instead ofFreeCADGui.*platform internals. This creates a single point of adaptation during upstream rebases — update the SDK wrappers, not every addon. -
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.