# 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/) │ │ ┌──────────────────┐ ┌──────────────────┐ │ │ │ Silo │ │ Gears │ │ │ │ Open/Save/Commit│ │ Parametric gear │ │ │ │ Part numbering │ │ generation │ │ │ │ Revision control│ │ │ │ │ │ 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 `` 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 `` metadata. Developed and versioned independently as git submodules. Must declare `sdk` to use SDK APIs. Current addons: **silo** (PLM), **gears** (parametric gear generation). --- ## 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 `` extensions specifying version bounds, load priority, and dependencies. **Default workbench:** `PartDesignWorkbench` (set in `PreferencePacks/KindredCreate/KindredCreate.cfg`). **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 `sdk` and uses `kindred_sdk` for overlay registration and theme tokens. Gears also depends on the SDK. The former ztools addon was removed from the build (#344) and archived to `reference/ztools/` (#345) as part of the UI/UX rework (#346); its commands will be reimplemented through the KCSDK system. ### 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:** Implement a proper `Create::FlipPocket` C++ feature inheriting from `PartDesign::ProfileBased`. **Rationale:** The former ztools Python implementation created a standard Pocket then applied 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 **Decision:** Deferred. The former Python approach was functional. Revisit as part of the KCSDK-driven command reimplementation (#346). ### 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 | DONE | C++ theme engine | | 5 | #354 | DONE | Toolbar provider system (IToolbarProvider) | | 6 | #355 | DONE | Menu and action system | | 7 | #356 | DONE | 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.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` with `py::gil_scoped_acquire` before every invocation. - **PySide widget bridging** — `WidgetBridge::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.** Addon versions are pinned git submodule commits. Updates are deliberate: ```bash cd mods/silo && git pull origin main && cd ../.. git add mods/silo && git commit -m "Update silo submodule" ``` 5. **Python-first approach.** C++ extensions are deferred until Python cannot achieve the requirement. 6. **Graceful degradation.** The addon loader skips addons that fail validation or loading. Each addon load is wrapped in try/except with console logging. Any addon can 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` `` extensions. This replaces hardcoded load lists and enables third-party addons in the future.