docs: update architecture docs for addon-first model (#255)
Some checks failed
Build and Test / build (pull_request) Failing after 2m1s

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.
This commit is contained in:
2026-02-17 12:38:18 -06:00
parent 68380357fb
commit 252e2c3b3e
3 changed files with 169 additions and 77 deletions

View File

@@ -112,7 +112,9 @@ Addons extend this through the Python API:
### Addon integration ### Addon integration
Both ztools and Silo are loaded by the `src/Mod/Create/` bootstrap module, which executes their `Init.py` and `InitGui.py` files at startup. Neither requires the user to switch workbenches. Instead, they register commands and use the editing context system to make those commands visible in the appropriate situations. Addons in `mods/` are loaded by a manifest-driven loader (`src/Mod/Create/addon_loader.py`). Each addon provides a `package.xml` with `<kindred>` extensions declaring version bounds, load priority, and dependencies. The loader resolves dependencies via topological sort and loads addons in order: **sdk** (0) → **ztools** (50) → **silo** (60).
Addons call platform APIs through the **kindred-addon-sdk** (`mods/sdk/kindred_sdk/`) rather than `FreeCADGui.*` internals directly. The SDK provides stable wrappers for editing contexts, theme tokens, FileOrigin registration, and dock panels.
ztools uses a `WorkbenchManipulator` plus `injectEditingCommands()` to add its tools to PartDesign, Assembly, and Spreadsheet contexts. Silo registers an overlay that adds the "Silo Origin" toolbar whenever the active document contains Silo tracking properties (`SiloItemId`, `SiloPartNumber`). ztools uses a `WorkbenchManipulator` plus `injectEditingCommands()` to add its tools to PartDesign, Assembly, and Spreadsheet contexts. Silo registers an overlay that adds the "Silo Origin" toolbar whenever the active document contains Silo tracking properties (`SiloItemId`, `SiloPartNumber`).
@@ -179,13 +181,14 @@ create/
│ │ ├── Stylesheets/ # QSS theme files │ │ ├── Stylesheets/ # QSS theme files
│ │ └── PreferencePacks/ # Theme and preference configurations │ │ └── PreferencePacks/ # Theme and preference configurations
│ ├── Mod/ # FreeCAD modules (PartDesign, Assembly, Sketcher, ...) │ ├── Mod/ # FreeCAD modules (PartDesign, Assembly, Sketcher, ...)
│ │ └── Create/ # Kindred bootstrap module -- loads ztools and Silo │ │ └── Create/ # Kindred Create module (Python loader + C++ scaffold)
│ └── 3rdParty/ # Vendored dependencies │ └── 3rdParty/ # Vendored dependencies
│ ├── OndselSolver/ # Assembly constraint solver (forked) │ ├── OndselSolver/ # Assembly constraint solver (forked)
│ └── GSL/ # Microsoft Guidelines Support Library │ └── GSL/ # Microsoft Guidelines Support Library
├── mods/ # Kindred addon modules (git submodules) ├── mods/ # Kindred addon modules
│ ├── ztools/ # ztools command provider │ ├── sdk/ # Addon SDK — stable API contract (priority 0)
── silo/ # Silo PLM workbench ── ztools/ # ztools command provider (submodule, priority 50)
│ └── silo/ # Silo PLM workbench (submodule, priority 60)
├── resources/ # Branding, icons, desktop integration, MIME types ├── resources/ # Branding, icons, desktop integration, MIME types
├── package/ # Packaging scripts ├── package/ # Packaging scripts
│ ├── debian/ # .deb build script │ ├── debian/ # .deb build script

View File

@@ -5,42 +5,116 @@
``` ```
FreeCAD startup FreeCAD startup
└─ src/Mod/Create/Init.py └─ src/Mod/Create/Init.py
└─ setup_kindred_addons() └─ addon_loader.load_addons(gui=False)
├─ exec(mods/ztools/ztools/Init.py) ├─ scan_addons("mods/") — find package.xml manifests
exec(mods/silo/freecad/Init.py) parse_manifest() — extract <kindred> extensions
├─ validate_manifest() — check min/max_create_version
├─ resolve_load_order() — topological sort by <dependency>
└─ for each addon in order:
├─ add addon dir to sys.path
├─ exec(Init.py)
└─ register in AddonRegistry (FreeCAD.KindredAddons)
└─ src/Mod/Create/InitGui.py └─ src/Mod/Create/InitGui.py
├─ setup_kindred_workbenches() ├─ addon_loader.load_addons(gui=True)
exec(mods/ztools/ztools/InitGui.py) for each addon in order:
└─ schedules deferred _register() (2000ms) └─ exec(InitGui.py)
├─ imports ZTools commands ├─ sdk (priority 0): logs "SDK loaded"
├─ installs _ZToolsManipulator (global) ├─ ztools (priority 50): schedules deferred _register() (2000ms)
└─ injects commands into editing contexts │ ├─ imports ZTools commands
└─ exec(mods/silo/freecad/InitGui.py) │ ├─ installs _ZToolsManipulator (global)
├─ registers SiloWorkbench │ └─ injects commands into editing contexts
└─ schedules deferred Silo overlay registration (2500ms) └─ silo (priority 60): registers SiloWorkbench
│ └─ schedules deferred Silo overlay registration (2500ms)
├─ EditingContextResolver singleton created (MainWindow constructor) ├─ EditingContextResolver singleton created (MainWindow constructor)
│ ├─ registers built-in contexts (PartDesign, Sketcher, Assembly, Spreadsheet) │ ├─ registers built-in contexts (PartDesign, Sketcher, Assembly, Spreadsheet)
│ ├─ connects to signalInEdit/signalResetEdit/signalActiveDocument/signalActivateView │ ├─ connects to signalInEdit/signalResetEdit/signalActiveDocument/signalActivateView
│ └─ BreadcrumbToolBar connected to contextChanged signal │ └─ BreadcrumbToolBar connected to contextChanged signal
└─ Deferred setup (QTimer): └─ Deferred setup (QTimer):
├─ 500ms: _register_kc_format() → .kc file format
├─ 1500ms: _register_silo_origin() → registers Silo FileOrigin ├─ 1500ms: _register_silo_origin() → registers Silo FileOrigin
├─ 2000ms: _setup_silo_auth_panel() → "Database Auth" dock ├─ 2000ms: _setup_silo_auth_panel() → "Database Auth" dock
├─ 2000ms: ZTools _register() → commands + manipulator ├─ 2000ms: ZTools _register() → commands + manipulator
├─ 2500ms: Silo overlay registration → "Silo Origin" toolbar overlay ├─ 2500ms: Silo overlay registration → "Silo Origin" toolbar overlay
├─ 3000ms: _check_silo_first_start() → settings prompt ├─ 3000ms: _check_silo_first_start() → settings prompt
├─ 4000ms: _setup_silo_activity_panel() → "Database Activity" dock (SSE) ├─ 4000ms: _setup_silo_activity_panel() → "Database Activity" dock
└─ 10000ms: _check_for_updates() → update checker (Gitea API) └─ 10000ms: _check_for_updates() → update checker (Gitea API)
``` ```
### Addon lifecycle
Each addon in `mods/` provides a `package.xml` manifest with a `<kindred>` extension block:
```xml
<kindred>
<min_create_version>0.1.0</min_create_version>
<load_priority>50</load_priority>
<pure_python>true</pure_python>
<dependencies>
<dependency>sdk</dependency>
</dependencies>
</kindred>
```
The loader (`addon_loader.py`) processes addons in this order:
1. **Scan** — find all `mods/*/package.xml` files
2. **Parse** — extract `<kindred>` metadata (version bounds, priority, dependencies)
3. **Validate** — reject addons incompatible with the current Create version
4. **Resolve** — topological sort by `<dependency>` declarations, breaking ties by `<load_priority>`
5. **Load** — execute `Init.py` (console) then `InitGui.py` (GUI) for each addon
6. **Register** — populate `FreeCAD.KindredAddons` registry with addon state
Current load order: **sdk** (0) → **ztools** (50) → **silo** (60)
## Key source layout ## Key source layout
``` ```
src/Mod/Create/ Kindred bootstrap module (Python) src/Mod/Create/ Kindred Create module
├── Init.py Adds mods/ addon paths, loads Init.py files ├── Init.py Console bootstrap — loads addons via manifest-driven loader
├── InitGui.py Loads workbenches, installs Silo manipulators ├── InitGui.py GUI bootstrap — loads addons, Silo integration, update checker
├── addon_loader.py Manifest-driven addon loader with dependency resolution
├── kc_format.py .kc file format round-trip preservation
├── version.py.in CMake template → version.py (build-time) ├── version.py.in CMake template → version.py (build-time)
── update_checker.py Checks Gitea releases API for updates ── update_checker.py Checks Gitea releases API for updates
├── CreateGlobal.h C++ export macros (CreateExport, CreateGuiExport)
├── App/ C++ App library (CreateApp.so)
│ ├── AppCreate.cpp Module entry point — PyMOD_INIT_FUNC(CreateApp)
│ └── AppCreatePy.cpp Python module object (Py::ExtensionModule)
└── Gui/ C++ Gui library (CreateGui.so)
├── AppCreateGui.cpp Module entry point — PyMOD_INIT_FUNC(CreateGui)
└── AppCreateGuiPy.cpp Python module object (Py::ExtensionModule)
mods/sdk/ [dir] Kindred addon SDK — stable API contract
├── package.xml Manifest (priority 0, no dependencies)
├── kindred_sdk/
│ ├── __init__.py Public API re-exports
│ ├── context.py Editing context wrappers (register_context, register_overlay, ...)
│ ├── theme.py YAML-driven palette system (get_theme_tokens, load_palette, Palette)
│ ├── origin.py FileOrigin registration (register_origin, unregister_origin)
│ ├── dock.py Deferred dock panel helper (register_dock_panel)
│ ├── compat.py Version detection (create_version, freecad_version)
│ └── palettes/
│ └── catppuccin-mocha.yaml 26 colors + 14 semantic roles
└── Init.py / InitGui.py Minimal log messages
mods/ztools/ [submodule] command provider (not a workbench)
├── package.xml Manifest (priority 50, depends on sdk)
├── ztools/InitGui.py Deferred command registration + _ZToolsManipulator
├── ztools/ztools/
│ ├── commands/ Datum, pattern, pocket, assembly, spreadsheet
│ ├── datums/core.py Datum creation via Part::AttachExtension
│ └── resources/ Icons (SDK theme tokens), theme utilities
└── CatppuccinMocha/ Theme preference pack (QSS)
mods/silo/ [submodule → silo-mod.git] FreeCAD workbench
├── freecad/package.xml Manifest (priority 60, depends on sdk)
├── silo-client/ [submodule → silo-client.git] shared API client
│ └── silo_client/ SiloClient, SiloSettings, CATEGORY_NAMES
└── freecad/ FreeCAD workbench (Python)
├── InitGui.py SiloWorkbench + overlay registration (via SDK)
├── silo_commands.py Commands + FreeCADSiloSettings adapter
└── silo_origin.py FileOrigin backend for Silo (via SDK)
src/Gui/EditingContext.h/.cpp EditingContextResolver singleton + context registry src/Gui/EditingContext.h/.cpp EditingContextResolver singleton + context registry
src/Gui/BreadcrumbToolBar.h/.cpp Color-coded breadcrumb toolbar (Catppuccin Mocha) src/Gui/BreadcrumbToolBar.h/.cpp Color-coded breadcrumb toolbar (Catppuccin Mocha)
@@ -49,22 +123,6 @@ src/Gui/CommandOrigin.cpp Origin_Commit/Pull/Push/Info/BOM commands
src/Gui/OriginManager.h/.cpp Origin lifecycle management src/Gui/OriginManager.h/.cpp Origin lifecycle management
src/Gui/OriginSelectorWidget.h/.cpp UI for origin selection src/Gui/OriginSelectorWidget.h/.cpp UI for origin selection
mods/ztools/ [submodule] command provider (not a workbench)
├── ztools/InitGui.py Deferred command registration + _ZToolsManipulator
├── ztools/ztools/
│ ├── commands/ Datum, pattern, pocket, assembly, spreadsheet
│ ├── datums/core.py Datum creation via Part::AttachExtension
│ └── resources/ Icons, theme utilities
└── CatppuccinMocha/ Theme preference pack (QSS)
mods/silo/ [submodule -> silo-mod.git] FreeCAD workbench
├── silo-client/ [submodule -> silo-client.git] shared API client
│ └── silo_client/ SiloClient, SiloSettings, CATEGORY_NAMES
└── freecad/ FreeCAD workbench (Python)
├── InitGui.py SiloWorkbench + Silo overlay context registration
├── silo_commands.py Commands + FreeCADSiloSettings adapter
└── silo_origin.py FileOrigin backend for Silo
src/Gui/Stylesheets/ QSS themes and SVG assets src/Gui/Stylesheets/ QSS themes and SVG assets
src/Gui/PreferencePacks/ KindredCreate preference pack (cfg + build-time QSS) src/Gui/PreferencePacks/ KindredCreate preference pack (cfg + build-time QSS)
``` ```

File diff suppressed because one or more lines are too long