All checks were successful
Build and Test / build (pull_request) Successful in 29m15s
Update documentation across 5 files to reflect changes from #388 (manifest validation) and #391 (per-document origin bindings): - CLAUDE.md: expand addon loading section with 6-step pipeline, add per-document origin functions to SDK API list - ARCHITECTURE.md: update bootstrap flow diagram with validate_dependencies() step, expand lifecycle to 7 steps - create-module-bootstrap.md: rewrite pipeline steps with validation detail, add pipeline functions to dependency chain diagram - package-xml-schema.md: add parse-time validation rules to field reference table, update version/dependency/context sections - writing-an-addon.md: add validation summary after priority table Refs #388, #391
8.6 KiB
8.6 KiB
Architecture
Bootstrap flow
FreeCAD startup
└─ src/Mod/Create/Init.py
└─ addon_loader.load_addons(gui=False)
├─ scan_addons("mods/") — find package.xml manifests
├─ parse_manifest() — extract <kindred> extensions, validate types/formats
├─ validate_dependencies() — cross-check deps against discovered addons
├─ validate_manifest() — check version bounds, paths (errors accumulated)
├─ 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
├─ addon_loader.load_addons(gui=True)
│ └─ for each addon in order:
│ └─ exec(InitGui.py)
│ ├─ sdk (priority 0): logs "SDK loaded"
│ ├─ solver (priority 10): registers KindredSolverBackend
│ ├─ gears (priority 40): registers GearsWorkbench
│ ├─ datums (priority 45): registers Create_DatumCreator
│ └─ silo (priority 60): registers SiloWorkbench
│ └─ schedules deferred Silo setup (overlay, panels, observer)
├─ EditingContextResolver singleton created (MainWindow constructor)
│ ├─ registers built-in contexts (PartDesign, Sketcher, Assembly, Spreadsheet)
│ ├─ connects to signalInEdit/signalResetEdit/signalActiveDocument/signalActivateView
│ └─ BreadcrumbToolBar connected to contextChanged signal
└─ Deferred setup (QTimer):
Create core (src/Mod/Create/InitGui.py):
├─ 500ms: _register_kc_format() → .kc file format
└─ 10000ms: _check_for_updates() → update checker (Gitea API)
Silo addon (mods/silo/InitGui.py):
├─ 500ms: kindred:// URL handler
├─ 600ms: document observer (.kc tree building)
├─ 2000ms: auth dock panel (via kindred_sdk.register_dock_panel)
├─ 2500ms: Silo overlay registration → "Silo Origin" toolbar overlay
├─ 3000ms: first-start settings check
└─ 4000ms: activity dock panel (via kindred_sdk.register_dock_panel)
Addon lifecycle
Each addon in mods/ provides a package.xml manifest with a <kindred> extension block:
<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:
- Scan — find all
mods/*/package.xmlfiles - Parse — extract
<kindred>metadata (version bounds, priority, dependencies); validate field types and formats (load_priority must be int, version strings must be dotted-numeric, context IDs must be alphanumeric/dots/underscores) - Validate dependencies — cross-check all declared dependency names against discovered addon names
- Validate manifests — reject addons incompatible with the current Create version, missing workbench paths, or lacking Init files; all errors accumulated per-addon in
AddonManifest.errors - Resolve — topological sort by
<dependency>declarations, breaking ties by<load_priority>; addons with errors are excluded - Load — execute
Init.py(console) thenInitGui.py(GUI) for each addon - Register — populate
FreeCAD.KindredAddonsregistry with addon state
Current load order: sdk (0) → solver (10) → gears (40) → datums (45) → silo (60)
Key source layout
src/Mod/Create/ Kindred Create module
├── Init.py Console bootstrap — loads addons via manifest-driven loader
├── 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)
├── 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/gears/ [submodule → gears.git] Gears workbench
├── package.xml Manifest (priority 40, depends on sdk)
└── ... Parametric gear generation
mods/solver/ [submodule → solver.git] Solver addon
└── ... Solver plugin support
mods/datums/ [submodule → datums.git] Unified datum creator
├── package.xml Manifest (priority 45, depends on sdk)
├── Init.py / InitGui.py Bootstrap
└── datums/ Python package (command, core, panel, detection, edit_panel)
mods/silo/ [submodule → silo-mod.git] PLM workbench
├── package.xml Manifest (priority 60, depends on sdk)
├── Init.py sys.path setup for silo-client
├── InitGui.py Consolidated GUI bootstrap (workbench, panels, observer, overlay)
├── silo-client/ [submodule → silo-client.git] shared API client
│ └── silo_client/ SiloClient, SiloSettings, CATEGORY_NAMES
└── freecad/ FreeCAD workbench (Python)
├── silo_commands.py Commands + FreeCADSiloSettings adapter
└── silo_origin.py FileOrigin backend for Silo (via SDK)
src/Gui/SDK/ KCSDK C++ shared library (libKCSDK.so)
├── KCSDKGlobal.h DLL export macros
├── Types.h Plain C++ types (ContextDef, DockArea, PanelPersistence)
├── IPanelProvider.h Abstract dock panel interface
├── WidgetBridge.h/.cpp PySide QWidget <-> C++ QWidget* (via Gui::PythonWrapper)
├── SDKRegistry.h/.cpp Singleton registry — contexts, panels, providers
└── bindings/ pybind11 module (kcsdk.so)
├── kcsdk_py.cpp Module definition — enums, functions, classes
├── PyIPanelProvider.h Trampoline for Python subclassing
└── PyProviderHolder.h GIL-safe forwarding wrapper
src/Gui/EditingContext.h/.cpp EditingContextResolver singleton + context registry
src/Gui/BreadcrumbToolBar.h/.cpp Color-coded breadcrumb toolbar (Catppuccin Mocha)
src/Gui/FileOrigin.h/.cpp FileOrigin base class + LocalFileOrigin
src/Gui/CommandOrigin.cpp Origin_Commit/Pull/Push/Info/BOM commands
src/Gui/OriginManager.h/.cpp Origin lifecycle management
src/Gui/OriginSelectorWidget.h/.cpp UI for origin selection
src/Gui/Stylesheets/ QSS themes and SVG assets
src/Gui/PreferencePacks/ KindredCreate preference pack (cfg + build-time QSS)
See INTEGRATION_PLAN.md for architecture layers and phase status.