docs: remove stale documentation and update for post-ztools architecture #369

Merged
forbes merged 1 commits from docs/stale-doc-cleanup into main 2026-03-02 19:03:52 +00:00
11 changed files with 53 additions and 1045 deletions
Showing only changes of commit de1b79255c - Show all commits

File diff suppressed because one or more lines are too long

View File

@@ -20,10 +20,7 @@ FreeCAD startup
│ └─ for each addon in order:
│ └─ exec(InitGui.py)
│ ├─ sdk (priority 0): logs "SDK loaded"
│ ├─ ztools (priority 50): schedules deferred _register() (2000ms)
│ │ ├─ imports ZTools commands
│ │ ├─ installs _ZToolsManipulator (global)
│ │ └─ injects commands into editing contexts
│ ├─ gears (priority 40): registers GearsWorkbench
│ └─ silo (priority 60): registers SiloWorkbench
│ └─ schedules deferred Silo overlay registration (2500ms)
├─ EditingContextResolver singleton created (MainWindow constructor)
@@ -34,7 +31,6 @@ FreeCAD startup
├─ 500ms: _register_kc_format() → .kc file format
├─ 1500ms: _register_silo_origin() → registers Silo FileOrigin
├─ 2000ms: _setup_silo_auth_panel() → "Database Auth" dock
├─ 2000ms: ZTools _register() → commands + manipulator
├─ 2500ms: Silo overlay registration → "Silo Origin" toolbar overlay
├─ 3000ms: _check_silo_first_start() → settings prompt
├─ 4000ms: _setup_silo_activity_panel() → "Database Activity" dock
@@ -65,7 +61,7 @@ The loader (`addon_loader.py`) processes addons in this order:
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)
Current load order: **sdk** (0) → **gears** (40) → **silo** (60)
## Key source layout
@@ -98,14 +94,12 @@ mods/sdk/ [dir] Kindred addon SDK — stable API contract
│ └── 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/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/silo/ [submodule → silo-mod.git] FreeCAD workbench
├── freecad/package.xml Manifest (priority 60, depends on sdk)

File diff suppressed because one or more lines are too long

View File

@@ -1,31 +1,8 @@
# Components
## ztools (command provider)
## Gears workbench
ZTools is no longer a standalone workbench. It registers as a command provider that
injects tools into the appropriate editing contexts via `WorkbenchManipulator` and
the `EditingContextResolver` system.
**Registered commands (9):**
| Command | Function | Injected Into |
|---------|----------|---------------|
| `ZTools_DatumCreator` | Create datum planes, axes, points (16 modes) | PartDesign Helper Features |
| `ZTools_DatumManager` | Manage existing datum objects | PartDesign Helper Features |
| `ZTools_EnhancedPocket` | Flip-side pocket (cut outside sketch profile) | PartDesign Modeling Features |
| `ZTools_RotatedLinearPattern` | Linear pattern with incremental rotation | PartDesign Transformation Features |
| `ZTools_AssemblyLinearPattern` | Pattern assembly components linearly | Assembly |
| `ZTools_AssemblyPolarPattern` | Pattern assembly components around axis | Assembly |
| `ZTools_SpreadsheetStyle{Bold,Italic,Underline}` | Text style toggles | Spreadsheet |
| `ZTools_SpreadsheetAlign{Left,Center,Right}` | Cell alignment | Spreadsheet |
| `ZTools_Spreadsheet{BgColor,TextColor,QuickAlias}` | Colors and alias creation | Spreadsheet |
**Integration** via `_ZToolsManipulator` (WorkbenchManipulator) and `injectEditingCommands()`:
- Commands are injected into native workbench toolbars (PartDesign, Assembly, Spreadsheet)
- Context toolbar injections ensure commands appear when the relevant editing context is active
- PartDesign menu items inserted after `PartDesign_Boolean`
**Datum types (7):** offset_from_face, offset_from_plane, midplane, 3_points, normal_to_edge, angled, tangent_to_cylinder. All except tangent_to_cylinder use `Part::AttachExtension` for automatic parametric updates.
Gears (`mods/gears/`) is a default addon providing parametric gear generation. Added as a submodule in the `feat/gears-addon` branch and merged to main.
---
@@ -110,10 +87,6 @@ Notable theme customizations beyond standard Catppuccin colors:
`silo-auth.svg`, `silo-bom.svg`, `silo-commit.svg`, `silo-info.svg`, `silo-new.svg`, `silo-open.svg`, `silo-pull.svg`, `silo-push.svg`, `silo-save.svg`, `silo.svg`
### Missing icons
3 command icon names have no corresponding SVG file: `silo-tag`, `silo-rollback`, `silo-status`. The `_icon()` function returns an empty string for these, so `Silo_TagProjects`, `Silo_Rollback`, and `Silo_SetStatus` render without toolbar icons.
### Palette
All silo-* icons use the Catppuccin Mocha color scheme. See `icons/kindred/README.md` for palette specification and icon design standards.

View File

@@ -18,11 +18,11 @@ Strategy for integrating ztools and Silo as built-in addons while maintaining cl
├─────────────────────────────────────────────────────────────┤
│ Layer 5: Kindred Addons (mods/) │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ ztools │ │ Silo │ │
│ │ Datum Creator │ │ Open/Save/Commit│ │
│ │ Enhanced Pocket │ │ Part numbering │ │
│ │ Assembly Patterns│ │ Revision control│ │
│ │ Spreadsheet fmt │ │ BOM management │ │
│ │ Silo │ │ Gears │ │
│ │ Open/Save/Commit│ │ Parametric gear │ │
│ │ Part numbering │ │ generation │ │
│ │ Revision control│ │ │ │
│ │ BOM management │ │ │ │
│ └──────────────────┘ └──────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ Layer 4: Kindred Addon SDK (mods/sdk/) │
@@ -91,7 +91,7 @@ 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.
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. Current addons: **silo** (PLM), **gears** (parametric gear generation).
---
@@ -101,7 +101,7 @@ Pure Python addons with `package.xml` manifests. Self-contained with `Init.py`,
**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.
**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.
@@ -111,7 +111,7 @@ Pure Python addons with `package.xml` manifests. Self-contained with `Init.py`,
**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.
**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. 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
@@ -121,17 +121,16 @@ Pure Python addons with `package.xml` manifests. Self-contained with `Init.py`,
### 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`.
**Goal:** Implement 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.
**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
- 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.
**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)
@@ -192,10 +191,10 @@ FreeCADGui (EditingContextResolver, DockWindowManager, OriginManager, ...)
| 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 |
| 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:**
@@ -221,15 +220,15 @@ FreeCADGui (EditingContextResolver, DockWindowManager, OriginManager, ...)
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:
4. **Version synchronization via submodule pins.** Addon versions are pinned git submodule commits. Updates are deliberate:
```bash
cd mods/ztools && git pull origin main && cd ../..
git add mods/ztools && git commit -m "Update ztools submodule"
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. The AttachExtension approach for datums validated this strategy.
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. The SDK, ztools, and Silo can all be absent without breaking the bootstrap.
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.

View File

@@ -1,90 +0,0 @@
# Known Issues
## Issues
### Critical
1. ~~**QSS duplication.**~~ Resolved. The canonical QSS lives in `src/Gui/Stylesheets/KindredCreate.qss`. The PreferencePacks copy is now generated at build time via `configure_file()` in `src/Gui/PreferencePacks/CMakeLists.txt`. The unused `resources/preferences/KindredCreate/` directory has been removed.
2. ~~**WorkbenchManipulator timing.**~~ Resolved. ZTools is no longer a workbench. Commands are registered via a deferred `QTimer.singleShot(2000ms)` in `InitGui.py`, which activates dependent workbenches first, then imports ZTools commands and installs the `_ZToolsManipulator`. The `EditingContextResolver` handles toolbar visibility based on editing context.
3. ~~**Silo shortcut persistence.**~~ Resolved. `Silo_ToggleMode` removed; file operations now delegate to the selected origin via the unified origin system.
### High
4. **Silo authentication not production-hardened.** Local auth (bcrypt) works end-to-end. LDAP (FreeIPA) and OIDC (Keycloak) backends are coded but depend on infrastructure not yet deployed. FreeCAD client has `Silo_Auth` dock panel for login and API token management. Server has session middleware (`alexedwards/scs`), CSRF protection (`nosurf`), and role-based access control (admin/editor/viewer). Migration `009_auth.sql` adds users, api_tokens, and sessions tables.
5. **No unit tests.** Zero test coverage for ztools and Silo FreeCAD commands. Silo Go backend also lacks tests.
6. **Assembly solver datum handling is minimal.** `UtilsAssembly.findPlacement()` handles standard shapes (faces, edges, vertices) and `App::Line` origin objects. It does not extract placement from `PartDesign::Plane` or `PartDesign::Point` datum objects — when no element is selected, it returns a default `App.Placement()`. This means assembly joints referencing datum planes/points may produce incorrect placement.
### Medium
7. **`Silo_BOM` requires Silo-tracked document.** Depends on `SiloPartNumber` property. Unregistered documents show a warning with no registration path.
8. **PartDesign menu insertion fragility.** `_ZToolsPartDesignManipulator.modifyMenuBar()` inserts after `PartDesign_Boolean`. If upstream renames this command, insertions silently fail.
9. **tangent_to_cylinder falls back to manual placement.** TangentPlane MapMode requires a vertex reference not collected by the current UI.
10. ~~**`delete_bom_entry()` bypasses error normalization.**~~ Resolved. `delete_bom_entry()` uses `self._request("DELETE", ...)` which routes through `SiloClient._request()` with proper error handling.
11. ~~**Missing Silo icons.**~~ Resolved. All three icons now exist: `silo-tag.svg`, `silo-rollback.svg`, `silo-status.svg` in `mods/silo/freecad/resources/icons/`.
### Fixed (retain for reference)
12. **OndselSolver Newton-Raphson convergence.** `NewtonRaphson::isConvergedToNumericalLimit()` compared `dxNorms->at(iterNo)` to itself instead of `dxNorms->at(iterNo - 1)`. This prevented convergence detection on complex assemblies, causing solver exhaustion and "grounded object moved" warnings. Fixed in Kindred fork (`src/3rdParty/OndselSolver`). Needs upstreaming to `FreeCAD/OndselSolver`.
13. **Assembly solver crash on document restore.** `AssemblyObject::onChanged()` called `updateSolveStatus()` when the Group property changed during document restore, triggering the solver while child objects were still deserializing (SIGSEGV). Fixed with `isRestoring()` and `isPerformingTransaction()` guards at `src/Mod/Assembly/App/AssemblyObject.cpp:143`.
14. **`DlgSettingsGeneral::applyMenuIconSize` visibility.** The method was `private` but called from `StartupProcess.cpp`. Fixed by moving to `public` (PR #49). Also required `Dialog::` namespace qualifier in `StartupProcess.cpp`.
---
## Incomplete features
### Silo
| Feature | Status | Notes |
|---------|--------|-------|
| Authentication | Local auth complete | LDAP/OIDC backends coded, pending infrastructure. Auth dock panel available. |
| CSRF protection | Implemented | `nosurf` library on web form routes |
| File locking | Not implemented | Needed to prevent concurrent edits |
| Odoo ERP integration | Stub only | Returns "not yet implemented" |
| Part number date segments | Unknown | `formatDate()` reference is stale — function not found in codebase |
| Location/inventory APIs | Tables exist, no handlers | |
| CSV import rollback | Not implemented | `bom_handlers.go` |
| SSE event streaming | Implemented | Reconnect logic with exponential backoff |
| Database Activity panel | Implemented | Dock panel showing real-time server events |
| Start panel | Implemented | In-viewport start page with recent files and Silo integration |
### ztools
| Feature | Status | Notes |
|---------|--------|-------|
| Tangent-to-cylinder attachment | Manual fallback | No vertex ref in UI |
| Angled datum live editing | Incomplete | AttachmentOffset not updated in panel |
| Assembly pattern undo | Not implemented | |
---
## Next steps
1. **Authentication hardening** -- Deploy FreeIPA and Keycloak infrastructure. End-to-end test LDAP and OIDC flows. Harden token rotation and session expiry.
2. **BOM-Assembly bridge** -- Auto-populate Silo BOM from Assembly component links on save. See `docs/BOM_MERGE.md` for specification.
3. **File locking** -- Pessimistic locks on `Silo_Open` to prevent concurrent edits. Requires server-side lock table and client-side lock display.
4. ~~**Build system**~~ Done. CMake install rules in `src/Mod/Create/CMakeLists.txt` handle all `mods/` submodules.
5. **Test coverage** -- Unit tests for ztools datum creation, Silo FreeCAD commands, and Go API endpoints.
6. ~~**QSS consolidation**~~ Done. Canonical QSS is `src/Gui/Stylesheets/KindredCreate.qss`; PreferencePacks copy generated at build time via `configure_file()`.
7. **Update notification UI** -- Display in-app notification when a new release is available (issue #30). The update checker backend (`update_checker.py`) runs at startup; notification UI still needed.
8. **KC file format completion** -- Populate `silo_instance` and `revision_hash` in manifest.json. Implement write-back for history.json, approvals.json, dependencies.json. See `docs/KC_SPECIFICATION.md`.
9. **ztools SDK migration** -- Add `<kindred>` metadata to `mods/ztools/package.xml` (load priority, version bounds, SDK dependency). Migrate `InitGui.py` to use `kindred_sdk` APIs for context/overlay registration.
10. **DAG cross-item edges** -- Assembly constraints referencing geometry in child parts should populate `dag_cross_edges`. Deferred until assembly constraint model is finalized.

View File

@@ -1,395 +0,0 @@
# DAG Client Integration Contract
**Status:** Draft
**Last Updated:** 2026-02-13
This document describes what silo-mod and Headless Create runners need to implement to integrate with the Silo dependency DAG and worker system.
---
## 1. Overview
The DAG system has two client-side integration points:
1. **silo-mod workbench** (desktop) -- pushes DAG data to Silo on save or revision create.
2. **silorunner + silo-mod** (headless) -- extracts DAGs, validates features, and exports geometry as compute jobs.
Both share the same Python codebase in the silo-mod repository. Desktop users call the code interactively; runners call it headlessly via `create --console`.
---
## 2. DAG Sync Payload
Clients push feature trees to Silo via:
```
PUT /api/items/{partNumber}/dag
Authorization: Bearer <user_token or runner_token>
Content-Type: application/json
```
### 2.1 Request Body
```json
{
"revision_number": 3,
"nodes": [
{
"node_key": "Sketch001",
"node_type": "sketch",
"properties_hash": "a1b2c3d4e5f6...",
"metadata": {
"label": "Base Profile",
"constraint_count": 12
}
},
{
"node_key": "Pad001",
"node_type": "pad",
"properties_hash": "f6e5d4c3b2a1...",
"metadata": {
"label": "Main Extrusion",
"length": 25.0
}
}
],
"edges": [
{
"source_key": "Sketch001",
"target_key": "Pad001",
"edge_type": "depends_on"
}
]
}
```
### 2.2 Field Reference
**Nodes:**
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `node_key` | string | yes | Unique within item+revision. Use Create's internal object name (e.g. `Sketch001`, `Pad003`). |
| `node_type` | string | yes | One of: `sketch`, `pad`, `pocket`, `fillet`, `chamfer`, `constraint`, `body`, `part`, `datum`. |
| `properties_hash` | string | no | SHA-256 hex digest of the node's parametric inputs. Used for memoization. |
| `validation_state` | string | no | One of: `clean`, `dirty`, `validating`, `failed`. Defaults to `clean`. |
| `metadata` | object | no | Arbitrary key-value pairs for display or debugging. |
**Edges:**
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `source_key` | string | yes | The node that is depended upon. |
| `target_key` | string | yes | The node that depends on the source. |
| `edge_type` | string | no | One of: `depends_on` (default), `references`, `constrains`. |
**Direction convention:** Edges point from dependency to dependent. If Pad001 depends on Sketch001, the edge is `source_key: "Sketch001"`, `target_key: "Pad001"`.
### 2.3 Response
```json
{
"synced": true,
"node_count": 15,
"edge_count": 14
}
```
---
## 3. Computing properties_hash
The `properties_hash` enables memoization -- if a node's inputs haven't changed since the last validation, it can be skipped. Computing it:
```python
import hashlib
import json
def compute_properties_hash(feature_obj):
"""Hash the parametric inputs of a Create feature."""
inputs = {}
if feature_obj.TypeId == "Sketcher::SketchObject":
# Hash geometry + constraints
inputs["geometry_count"] = feature_obj.GeometryCount
inputs["constraint_count"] = feature_obj.ConstraintCount
inputs["geometry"] = str(feature_obj.Shape.exportBrep())
elif feature_obj.TypeId == "PartDesign::Pad":
inputs["length"] = feature_obj.Length.Value
inputs["type"] = str(feature_obj.Type)
inputs["reversed"] = feature_obj.Reversed
inputs["sketch"] = feature_obj.Profile[0].Name
# ... other feature types
canonical = json.dumps(inputs, sort_keys=True)
return hashlib.sha256(canonical.encode()).hexdigest()
```
The exact inputs per feature type are determined by what parametric values affect the feature's geometry. Include anything that, if changed, would require recomputation.
---
## 4. Feature Tree Walking
To extract the DAG from a Create document:
```python
import FreeCAD
def extract_dag(doc):
"""Walk a Create document and return nodes + edges."""
nodes = []
edges = []
for obj in doc.Objects:
# Skip non-feature objects
if not hasattr(obj, "TypeId"):
continue
node_type = classify_type(obj.TypeId)
if node_type is None:
continue
nodes.append({
"node_key": obj.Name,
"node_type": node_type,
"properties_hash": compute_properties_hash(obj),
"metadata": {
"label": obj.Label,
"type_id": obj.TypeId,
}
})
# Walk dependencies via InList (objects this one depends on)
for dep in obj.InList:
if hasattr(dep, "TypeId") and classify_type(dep.TypeId):
edges.append({
"source_key": dep.Name,
"target_key": obj.Name,
"edge_type": "depends_on",
})
return nodes, edges
def classify_type(type_id):
"""Map Create TypeIds to DAG node types."""
mapping = {
"Sketcher::SketchObject": "sketch",
"PartDesign::Pad": "pad",
"PartDesign::Pocket": "pocket",
"PartDesign::Fillet": "fillet",
"PartDesign::Chamfer": "chamfer",
"PartDesign::Body": "body",
"Part::Feature": "part",
"Sketcher::SketchConstraint": "constraint",
}
return mapping.get(type_id)
```
---
## 5. When to Push DAG Data
Push the DAG to Silo in these scenarios:
| Event | Trigger | Who |
|-------|---------|-----|
| User saves in silo-mod | On save callback | Desktop silo-mod workbench |
| User creates a revision | After `POST /api/items/{pn}/revisions` succeeds | Desktop silo-mod workbench |
| Runner extracts DAG | After `create-dag-extract` job completes | silorunner via `PUT /api/runner/jobs/{id}/dag` |
| Runner validates | After `create-validate` job, push updated validation states | silorunner via `PUT /api/runner/jobs/{id}/dag` |
---
## 6. Runner Entry Points
silo-mod must provide these Python entry points for headless invocation:
### 6.1 silo.runner.dag_extract
Extracts the feature DAG from a Create file and writes it as JSON.
```python
# silo/runner.py
def dag_extract(input_path, output_path):
"""
Extract feature DAG from a Create file.
Args:
input_path: Path to the .kc (Kindred Create) file.
output_path: Path to write the JSON output.
Output JSON format:
{
"nodes": [...], // Same format as DAG sync payload
"edges": [...]
}
"""
doc = FreeCAD.openDocument(input_path)
nodes, edges = extract_dag(doc)
with open(output_path, 'w') as f:
json.dump({"nodes": nodes, "edges": edges}, f)
FreeCAD.closeDocument(doc.Name)
```
### 6.2 silo.runner.validate
Rebuilds all features and reports pass/fail per node.
```python
def validate(input_path, output_path):
"""
Validate a Create file by rebuilding all features.
Output JSON format:
{
"valid": true/false,
"nodes": [
{
"node_key": "Pad001",
"state": "clean", // or "failed"
"message": null, // error message if failed
"properties_hash": "..."
}
]
}
"""
doc = FreeCAD.openDocument(input_path)
doc.recompute()
results = []
all_valid = True
for obj in doc.Objects:
if not hasattr(obj, "TypeId"):
continue
node_type = classify_type(obj.TypeId)
if node_type is None:
continue
state = "clean"
message = None
if hasattr(obj, "isValid") and not obj.isValid():
state = "failed"
message = f"Feature {obj.Label} failed to recompute"
all_valid = False
results.append({
"node_key": obj.Name,
"state": state,
"message": message,
"properties_hash": compute_properties_hash(obj),
})
with open(output_path, 'w') as f:
json.dump({"valid": all_valid, "nodes": results}, f)
FreeCAD.closeDocument(doc.Name)
```
### 6.3 silo.runner.export
Exports geometry to STEP, IGES, or other formats.
```python
def export(input_path, output_path, format="step"):
"""
Export a Create file to an external format.
Args:
input_path: Path to the .kc file.
output_path: Path to write the exported file.
format: Export format ("step", "iges", "stl", "obj").
"""
doc = FreeCAD.openDocument(input_path)
import Part
shapes = [obj.Shape for obj in doc.Objects if hasattr(obj, "Shape")]
compound = Part.makeCompound(shapes)
format_map = {
"step": "STEP",
"iges": "IGES",
"stl": "STL",
"obj": "OBJ",
}
Part.export([compound], output_path)
FreeCAD.closeDocument(doc.Name)
```
---
## 7. Headless Invocation
The `silorunner` binary shells out to Create (with silo-mod installed):
```bash
# DAG extraction
create --console -e "from silo.runner import dag_extract; dag_extract('/tmp/job/part.kc', '/tmp/job/dag.json')"
# Validation
create --console -e "from silo.runner import validate; validate('/tmp/job/part.kc', '/tmp/job/result.json')"
# Export
create --console -e "from silo.runner import export; export('/tmp/job/part.kc', '/tmp/job/output.step', 'step')"
```
**Prerequisites:** The runner host must have:
- Headless Create installed (Kindred's fork of FreeCAD)
- silo-mod installed as a Create addon (so `from silo.runner import ...` works)
- No display server required -- `--console` mode is headless
---
## 8. Validation Result Handling
After a runner completes a `create-validate` job, it should:
1. Read the result JSON.
2. Push updated validation states via `PUT /api/runner/jobs/{jobID}/dag`:
```json
{
"revision_number": 3,
"nodes": [
{"node_key": "Sketch001", "node_type": "sketch", "validation_state": "clean", "properties_hash": "abc..."},
{"node_key": "Pad001", "node_type": "pad", "validation_state": "failed", "properties_hash": "def..."}
],
"edges": [
{"source_key": "Sketch001", "target_key": "Pad001"}
]
}
```
3. Complete the job via `POST /api/runner/jobs/{jobID}/complete` with the summary result.
---
## 9. SSE Events
Clients should listen for these events on `GET /api/events`:
| Event | Payload | When |
|-------|---------|------|
| `dag.updated` | `{item_id, part_number, revision_number, node_count, edge_count}` | After any DAG sync |
| `dag.validated` | `{item_id, part_number, valid, failed_count}` | After validation completes |
| `job.created` | `{job_id, definition_name, trigger, item_id}` | Job auto-triggered or manually created |
| `job.claimed` | `{job_id, runner_id, runner}` | Runner claims a job |
| `job.progress` | `{job_id, progress, message}` | Runner reports progress |
| `job.completed` | `{job_id, runner_id}` | Job finishes successfully |
| `job.failed` | `{job_id, runner_id, error}` | Job fails |
| `job.cancelled` | `{job_id, cancelled_by}` | Job cancelled by user |
---
## 10. Cross-Item Edges
For assembly constraints that reference geometry in child parts (e.g. a mate constraint between two parts), use the `dag_cross_edges` table. These edges bridge the BOM DAG and the feature DAG.
Cross-item edges are **not** included in the standard `PUT /dag` sync. They will be managed through a dedicated endpoint in a future iteration once the assembly constraint model in Create/silo-mod is finalized.
For now, the DAG sync covers intra-item dependencies only. Assembly-level interference detection uses the BOM DAG (`relationships` table) combined with per-item feature DAGs.

View File

@@ -1,26 +1,30 @@
# Kindred Create
**Last updated:** 2026-02-08
**Branch:** main @ `cf523f1d87a`
**Kindred Create:** v0.1.0
**FreeCAD base:** v1.0.0
**Last updated:** 2026-03-02
**Branch:** main @ `b0621f9731c`
**Kindred Create:** v0.1.5
**FreeCAD base:** v1.2.0
## Documentation
| Document | Contents |
|----------|----------|
| [ARCHITECTURE.md](ARCHITECTURE.md) | Bootstrap flow, source layout, submodules |
| [COMPONENTS.md](COMPONENTS.md) | ztools, Silo, Origin commands, theme, icons |
| [KNOWN_ISSUES.md](KNOWN_ISSUES.md) | Bugs, incomplete features, next steps |
| [COMPONENTS.md](COMPONENTS.md) | Silo, Gears, Origin commands, theme, icons |
| [INTEGRATION_PLAN.md](INTEGRATION_PLAN.md) | Architecture layers, integration phases |
| [CI_CD.md](CI_CD.md) | Build and release workflows |
| [INTER_SOLVER.md](INTER_SOLVER.md) | Inter-solver communication |
| [DAG_CLIENT_INTEGRATION.md](DAG_CLIENT_INTEGRATION.md) | DAG client integration (draft) |
| [BOM_MERGE.md](BOM_MERGE.md) | Bill of materials merge specification |
| [KC_SPECIFICATION.md](KC_SPECIFICATION.md) | .kc file format specification |
## Submodules
| Submodule | Path | Source | Pinned commit |
|-----------|------|--------|---------------|
| ztools | `mods/ztools` | `git.kindred-systems.com/forbes/ztools` | `3298d1c` |
| silo-mod | `mods/silo` | `git.kindred-systems.com/kindred/silo-mod` | `f9924d3` |
| silo-mod | `mods/silo` | `git.kindred-systems.com/kindred/silo-mod` | `cc6a79f` |
| gears | `mods/gears` | `git.kindred-systems.com/kindred/gears` | `1e26c39` |
| solver | `mods/solver` | `git.kindred-systems.com/kindred/solver` | `cd7f66f` |
| OndselSolver | `src/3rdParty/OndselSolver` | `git.kindred-systems.com/kindred/solver` | `fe41fa3` |
| GSL | `src/3rdParty/GSL` | `github.com/microsoft/GSL` | `756c91a` |
| AddonManager | `src/Mod/AddonManager` | `github.com/FreeCAD/AddonManager` | `01e242e` |
@@ -28,4 +32,6 @@
The silo submodule was split from a monorepo into three repos: `silo-client` (shared Python API client), `silo-mod` (FreeCAD workbench, used as Create's submodule), and `silo-calc` (LibreOffice Calc extension). The `silo-mod` repo includes `silo-client` as its own submodule.
OndselSolver is forked from `github.com/FreeCAD/OndselSolver` to carry a Newton-Raphson convergence fix (see [KNOWN_ISSUES.md](KNOWN_ISSUES.md#12)).
OndselSolver is forked from `github.com/FreeCAD/OndselSolver` to carry a Newton-Raphson convergence fix.
The 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.

View File

@@ -1,332 +0,0 @@
# Kindred Create Repository State Report
**Generated:** 2026-01-31
**Branch:** main
**Parent repo:** create-0070 @ `364a7057ef`
**Submodules:**
- ztools @ `8d1f195` (ztools-0065, main)
- silo @ `c778825` (silo-0062, main)
---
## Recent Changes (This Session)
### Assembly Solver Fix
- `610fd43` — PartDesign datum planes (including ZTools datums) now work
correctly as joint references in Assembly. `findPlacement()` in
`src/Mod/Assembly/UtilsAssembly.py` extracts geometry from
`PartDesign::Plane` and `PartDesign::Point` objects instead of returning
zero placements.
### ZTools Bug Fixes
- `665bdb2` — Three fixes in the ztools submodule:
- Removed `int()` wrapper from `getStandardButtons()` (Qt6/PySide6
compatibility — `StandardButton` enum is not int-castable).
- Guarded `_setup_ztools_viewprovider()` against C++ ViewProviders
that lack a `Proxy` attribute (`PartDesign::Plane` uses
`ViewProviderDatumPlane`, pure C++).
- Changed `setEditorMode(prop, 2)` to `setPropertyStatus(prop, "Hidden")`
for persistent attachment property hiding across save/reload.
### ZTools Parametric Datums via AttachExtension
- `2c716b4` — ZTools datum planes now leverage FreeCAD's built-in
`Part::AttachExtension` for automatic parametric updates. Instead of
`MapMode = "Deactivated"` with manual placement, each datum type maps to a
vanilla `MapMode` (`FlatFace`, `ThreePointsPlane`, `NormalToEdge`, etc.)
with appropriate `AttachmentSupport` and `AttachmentOffset`. Datums update
automatically when source geometry changes on recompute.
### Stylesheet Fixes (Uncommitted — Staged)
- **Tree branch indicators**: Created `branch_closed.svg` and
`branch_open.svg` in `images_dark-light/` with Catppuccin `#cdd6f4`
chevrons. Added `QTreeView::branch` image rules for expand/collapse states.
- **Spinbox/combobox arrows**: Synced all three QSS copies so the CSS
border-triangle arrow fix (previously only in `resources/preferences/`)
now applies at runtime via `src/Gui/Stylesheets/KindredCreate.qss`.
- **Header clipping**: Added `min-height: 20px` to `QHeaderView::section`.
- **QSS sync**: All four copies (`resources/preferences/`, `src/Gui/Stylesheets/`,
`src/Gui/PreferencePacks/`, `mods/ztools/CatppuccinMocha/`) are now
byte-identical. Merged dock widget padding and spreadsheet cell editor
styling improvements that existed only in the Stylesheets copy.
### ZTools-PartDesign Merge (Uncommitted — Staged)
- `_ZToolsPartDesignManipulator` in `mods/ztools/ztools/InitGui.py` uses
`Gui.addWorkbenchManipulator()` to inject ZTools commands into PartDesign's
C++ toolbars:
- `ZTools_DatumCreator` + `ZTools_DatumManager` → "Part Design Helper Features"
- `ZTools_EnhancedPocket` → "Part Design Modeling Features"
- `ZTools_RotatedLinearPattern` → "Part Design Transformation Features"
- Same commands also inserted into the Part Design menu after `PartDesign_Boolean`.
### Silo Enhancements (Uncommitted — Staged)
- **File menu integration**: `SiloMenuManipulator` in `src/Mod/Create/InitGui.py`
injects `Silo_New`, `Silo_Open`, `Silo_Save`, `Silo_Commit`, `Silo_Pull`,
`Silo_Push`, and `Silo_BOM` into the File menu across all workbenches.
- **Toolbar toggle**: `Silo_ToggleMode` checkable command swaps `Ctrl+O/S/N`
between standard FreeCAD file commands and Silo equivalents. Appended to the
global File toolbar via the manipulator.
- **SSL certificate browsing**: Settings dialog now includes a file browser for
custom CA certificates (`SslCertPath` preference). `_get_ssl_context()` loads
the custom cert before system CAs.
- **BOM integration**: Upstream BOM feature (`Silo_BOM` command with tabbed
dialog — BOM + Where Used) merged with local changes and added to the
Create File menu manipulator.
---
## Architecture Overview
```
create-0070/ Kindred Create (FreeCAD 1.0+ fork)
├── src/
│ ├── Mod/
│ │ ├── Assembly/ Assembly solver (OndselSolver)
│ │ ├── PartDesign/ Part modeling (C++ workbench)
│ │ ├── Sketcher/ 2D constraint sketcher
│ │ ├── Create/ Kindred bootstrap module (Python)
│ │ │ └── InitGui.py Loads ztools+silo, installs manipulators
│ │ └── ... Other FreeCAD modules
│ └── Gui/
│ ├── Stylesheets/ QSS themes + arrow/branch SVGs
│ ├── PreferencePacks/ Preference pack bundles
│ └── WorkbenchManipulatorPython.cpp Menu/toolbar injection API
├── mods/
│ ├── ztools/ [submodule] ztools-0065
│ │ └── ztools/
│ │ ├── InitGui.py ZToolsWorkbench + PartDesign manipulator
│ │ └── ztools/
│ │ ├── commands/ Datum, pattern, pocket, assembly, spreadsheet
│ │ ├── datums/core.py Datum creation with AttachExtension
│ │ └── resources/ Icons, theme utilities
│ └── silo/ [submodule] silo-0062
│ └── pkg/freecad/
│ ├── InitGui.py SiloWorkbench
│ └── silo_commands.py 12 commands + SiloClient API
└── resources/
└── preferences/KindredCreate/ Canonical QSS + preference pack
```
### Integration Flow
```
FreeCAD startup
└─ src/Mod/Create/InitGui.py exec()
├─ exec(mods/ztools/ztools/InitGui.py)
│ ├─ registers ZToolsWorkbench
│ └─ installs _ZToolsPartDesignManipulator (global)
├─ exec(mods/silo/pkg/freecad/InitGui.py)
│ └─ registers SiloWorkbench
└─ QTimer.singleShot(2000):
├─ _setup_silo_menu()
│ └─ installs SiloMenuManipulator (global)
│ ├─ modifyMenuBar: Silo commands in File menu
│ └─ modifyToolBars: Silo_ToggleMode in File toolbar
├─ _check_silo_first_start()
└─ _setup_silo_activity_panel()
```
---
## Submodule Status
### ztools (ztools-0065)
| Commit | Description |
|--------|-------------|
| `8d1f195` | Add PartDesign WorkbenchManipulator and sync Catppuccin theme |
| `005348b` | Leverage FreeCAD AttachExtension for parametric datum updates |
| `0e95d1c` | Fix Qt6 StandardButton TypeError and C++ ViewProvider Proxy errors |
| `98bd444` | Fix workbench init and spreadsheet syntax errors |
**Custom commands**: 9 registered
- `ZTools_DatumCreator`, `ZTools_DatumManager`
- `ZTools_RotatedLinearPattern`
- `ZTools_EnhancedPocket`
- `ZTools_AssemblyLinearPattern`, `ZTools_AssemblyPolarPattern`
- `ZTools_SpreadsheetStyle{Bold,Italic,Underline}`, `ZTools_SpreadsheetAlign{Left,Center,Right}`, `ZTools_Spreadsheet{BgColor,TextColor,QuickAlias}`
**Datum types supported**: offset_from_face, offset_from_plane, midplane,
3_points, normal_to_edge, angled, tangent_to_cylinder
### silo (silo-0062)
| Commit | Description |
|--------|-------------|
| `c778825` | Add Silo mode toggle, SSL cert browsing, and BOM menu integration |
| `8c06899` | (upstream) Various fixes |
| `bce7d5a` | Add BOM handling and routes to API and web UI |
| `3a79d89` | feat: add BOM system with API, database repository, and FreeCAD command |
| `8e44ed2` | Fix SIGSEGV: defer document open after dialog close |
**FreeCAD commands**: 12 registered
- `Silo_Open`, `Silo_New`, `Silo_Save`, `Silo_Commit`
- `Silo_Pull`, `Silo_Push`, `Silo_Info`, `Silo_BOM`
- `Silo_TagProjects`, `Silo_Rollback`, `Silo_SetStatus`
- `Silo_Settings`, `Silo_ToggleMode`
**API surface**: 38 REST routes covering items, revisions, files, BOM,
projects, schemas, and Odoo integration stubs. See
`mods/silo/docs/REPOSITORY_STATUS.md` for full route table.
**BOM API methods** (new):
- `get_bom()`, `get_bom_expanded()`, `get_bom_where_used()`
- `add_bom_entry()`, `update_bom_entry()`, `delete_bom_entry()`
---
## Potential Issues
### Critical
1. **Three QSS copies can drift again.** The canonical source is
`resources/preferences/KindredCreate/KindredCreate.qss`. The other copies
(`src/Gui/Stylesheets/`, `src/Gui/PreferencePacks/`, `mods/ztools/CatppuccinMocha/`)
must be kept in sync manually. Consider a build step or symlinks to
eliminate duplication.
2. **WorkbenchManipulator command registration timing.** The
`_ZToolsPartDesignManipulator` appends commands by name (e.g.
`ZTools_DatumCreator`). If the ZTools workbench has not been initialized
(first activation) when the user switches to PartDesign, the commands may
not be registered yet. The `Create/InitGui.py` `exec()` loads the
workbench class but `Initialize()` only runs on first activation. The
manipulator API tolerates missing commands silently (toolbar append
returns without error), but the buttons won't appear until ZTools
initializes. Mitigation: force-activate ZToolsWorkbench during Create
module load, or defer manipulator installation.
3. **Silo toggle mode shortcut persistence.** `_swap_shortcuts()` stores
original shortcuts in a module-level dict (`_original_shortcuts`). If
FreeCAD crashes with Silo mode ON, the original shortcuts are lost and
standard commands will have no keyboard shortcuts on next launch. Consider
persisting original shortcuts to preferences.
### High
4. **Silo has no authentication.** All API endpoints are publicly accessible.
Required before multi-user deployment. See
`mods/silo/docs/REPOSITORY_STATUS.md` for full list.
5. **No unit tests for silo FreeCAD commands or ztools.** Python code has zero
test coverage. The Go backend also lacks tests per the silo status report.
6. **Assembly solver `findPlacement()` geometry extraction is minimal.** The
fix at `UtilsAssembly.py:1006` extracts placement from `obj.Shape.Faces[0]`
for `PartDesign::Plane`. This works for planar datums but does not handle
edge cases like empty shapes or non-planar datum objects.
### Medium
7. **`Silo_BOM` depends on `get_tracked_object()`** which looks for a
`SiloPartNumber` property on document objects. Documents not registered
with Silo show a warning dialog. The UX could be improved with a
one-click registration flow from the BOM dialog.
8. **`_ZToolsPartDesignManipulator.modifyMenuBar()` inserts after
`PartDesign_Boolean`.** If upstream FreeCAD renames or removes this
command, the menu insertions silently fail. The toolbar appends (by
toolbar name) are more robust.
9. **ZTools `plane_tangent_to_cylinder` falls back to manual placement**
because the TangentPlane MapMode requires a vertex reference not currently
collected by the UI. This is the only datum type that does not benefit
from automatic parametric updates.
10. **Silo `delete_bom_entry()` uses raw `urllib.request`** instead of the
`_request()` helper method on `SiloClient`. This bypasses error
normalization. Should be refactored to use `self._request("DELETE", ...)`.
---
## Feature Stubs and TODOs
### From silo REPOSITORY_STATUS
| Feature | Status | Location |
|---------|--------|----------|
| Odoo ERP integration | Stub (returns "not yet implemented") | `internal/odoo/` |
| Part number date segments | Broken (`formatDate()` returns error) | `internal/partnum/generator.go:102` |
| Location/Inventory APIs | Tables exist, no handlers | `migrations/001_initial.sql` |
| File locking | Not implemented | — |
| Authentication/Authorization | Not implemented | — |
| CSRF protection | Not implemented | Web UI only |
| CSV import transaction rollback | Not implemented | `bom_handlers.go` |
### From ztools
| Feature | Status | Location |
|---------|--------|----------|
| Tangent-to-cylinder attachment | Manual fallback (no vertex ref) | `datums/core.py` |
| Angled datum live editing | AttachmentOffset rotation not updated in panel | `datum_viewprovider.py` |
| Assembly pattern undo support | Not implemented | `assembly_pattern_commands.py` |
### From Create integration plan
| Phase | Feature | Status |
|-------|---------|--------|
| 1 | Addon auto-loading | Done (`src/Mod/Create/InitGui.py`) |
| 2 | Enhanced Pocket as C++ feature | Not started |
| 3 | Datum C++ helpers | Not started (Python AttachExtension approach used instead) |
| 4 | Theme system refinement | Partially done (QSS synced, not moved to Create module) |
| 5 | Silo deep integration | Done (manipulator-based menu/toolbar injection) |
| 6 | Build system integration | Not started |
---
## File Change Summary (Uncommitted)
### Parent repo (create-0070)
| File | Change |
|------|--------|
| `resources/preferences/KindredCreate/KindredCreate.qss` | Branch indicators, header min-height, dock/actiongroup improvements, spreadsheet cell editor |
| `src/Gui/Stylesheets/KindredCreate.qss` | Synced with canonical |
| `src/Gui/PreferencePacks/KindredCreate/KindredCreate.qss` | Synced with canonical |
| `src/Gui/Stylesheets/images_dark-light/branch_closed.svg` | New: right-pointing chevron |
| `src/Gui/Stylesheets/images_dark-light/branch_open.svg` | New: down-pointing chevron |
| `src/Mod/Create/InitGui.py` | Expanded SiloMenuManipulator (BOM, full commands, toolbar toggle) |
| `mods/silo` | Submodule pointer updated |
| `mods/ztools` | Submodule pointer updated |
### ztools submodule (committed + pushed)
| File | Change |
|------|--------|
| `ztools/InitGui.py` | Added `_ZToolsPartDesignManipulator` |
| `CatppuccinMocha/CatppuccinMocha.qss` | Synced with canonical KindredCreate.qss |
### silo submodule (committed + pushed)
| File | Change |
|------|--------|
| `pkg/freecad/silo_commands.py` | SSL cert browsing, `Silo_ToggleMode`, BOM merge |
| `pkg/freecad/InitGui.py` | Added `Silo_ToggleMode` to toolbar |
---
## Silo Integration Path
Based on `mods/silo/docs/REPOSITORY_STATUS.md` and the existing
`docs/INTEGRATION_PLAN.md`, the integration path forward is:
### Completed
- Addon auto-loading via `src/Mod/Create/InitGui.py`
- Global File menu injection via `WorkbenchManipulator`
- Toolbar toggle for Silo mode (shortcut swapping)
- SSL certificate configuration for internal CAs
- BOM command integrated into File menu
### Next Steps
1. **Authentication** — LDAP/FreeIPA integration for multi-user. Silo server
needs auth middleware; FreeCAD client needs credential storage in preferences.
2. **BOM-Assembly bridge** — Auto-populate Silo BOM from FreeCAD Assembly
component links. When a user saves an assembly, extract child part numbers
from `Assembly_InsertLink` objects and sync to Silo BOM.
3. **File locking** — Pessimistic locks on checkout (`Silo_Open`) to prevent
concurrent edits. Requires server-side lock table and client-side
lock-status display.
4. **Status bar integration** — Show current Silo item part number, revision,
and sync status in FreeCAD's status bar. Use
`FreeCADGui.getMainWindow().statusBar()`.
5. **Build system** — CMake install rules for `mods/` submodules so `.deb`
packages include ztools and silo without manual intervention.

View File

@@ -10,7 +10,6 @@
- [Installation](./guide/installation.md)
- [Building from Source](./guide/building.md)
- [Workbenches](./guide/workbenches.md)
- [ztools](./guide/ztools.md)
- [Silo](./guide/silo.md)
- [Document Templates](./guide/templates.md)

View File

@@ -1,133 +0,0 @@
# ztools
ztools is a pure-Python FreeCAD workbench that consolidates part design, assembly, and sketcher tools into a single unified interface. It is the **default workbench** when Kindred Create launches.
- **Submodule path:** `mods/ztools/`
- **Source:** `git.kindred-systems.com/forbes/ztools`
- **Stats:** 6,400+ lines of code, 24+ command classes, 33 custom icons, 17 toolbars
## Commands
### Datum Creator (`ZTools_DatumCreator`)
Creates datum geometry (planes, axes, points) with 16 creation modes. The task panel auto-detects the geometry type from your selection and offers appropriate modes. Supports custom naming, spreadsheet linking, and body- or document-level creation.
### Datum Manager (`ZTools_DatumManager`)
Manages existing datums. (Stub — planned for Phase 1, Q1 2026.)
### Enhanced Pocket (`ZTools_EnhancedPocket`)
Extends FreeCAD's Pocket feature with **Flip Side to Cut** — a SOLIDWORKS-style feature that removes material *outside* the sketch profile rather than inside. Uses a Boolean Common operation internally. Supports all standard pocket types: Dimension, Through All, To First, Up To Face, Two Dimensions. Taper angle is supported for standard pockets (disabled for flipped).
### Rotated Linear Pattern (`ZTools_RotatedLinearPattern`)
Creates a linear pattern with incremental rotation per instance. Configure direction, spacing, number of occurrences, and cumulative or per-instance rotation. Source components are automatically hidden.
### Assembly Linear Pattern (`ZTools_AssemblyLinearPattern`)
Creates linear patterns of assembly components. Supports multi-component selection, direction vectors, total length or spacing modes, and creation as Links (recommended) or copies. Auto-detects the parent assembly.
### Assembly Polar Pattern (`ZTools_AssemblyPolarPattern`)
Creates polar (circular) patterns of assembly components. Supports custom or preset axes (X/Y/Z), full circle or custom angle, center point definition, and creation as Links or copies.
### Spreadsheet Formatting (9 commands)
| Command | Action |
|---------|--------|
| `ZTools_SpreadsheetStyleBold` | Toggle bold |
| `ZTools_SpreadsheetStyleItalic` | Toggle italic |
| `ZTools_SpreadsheetStyleUnderline` | Toggle underline |
| `ZTools_SpreadsheetAlignLeft` | Left align |
| `ZTools_SpreadsheetAlignCenter` | Center align |
| `ZTools_SpreadsheetAlignRight` | Right align |
| `ZTools_SpreadsheetBgColor` | Background color picker |
| `ZTools_SpreadsheetTextColor` | Text color picker |
| `ZTools_SpreadsheetQuickAlias` | Auto-create aliases from row/column labels |
## Datum creation modes
### Planes (7 modes)
| Mode | Description | Input |
|------|-------------|-------|
| Offset from Face | Offsets a planar face along its normal | Face + distance (mm) |
| Offset from Plane | Offsets an existing datum plane | Datum plane + distance (mm) |
| Midplane | Plane halfway between two parallel faces | Two parallel faces |
| 3 Points | Plane through three non-collinear points | Three vertices |
| Normal to Edge | Plane perpendicular to an edge at a parameter location | Edge + parameter (0.01.0) |
| Angled | Rotates a plane about an edge by a specified angle | Face + edge + angle (degrees) |
| Tangent to Cylinder | Plane tangent to a cylindrical face at an angular position | Cylindrical face + angle (degrees) |
### Axes (4 modes)
| Mode | Description | Input |
|------|-------------|-------|
| 2 Points | Axis through two points | Two vertices |
| From Edge | Axis along a linear edge | Linear edge |
| Cylinder Center | Axis along the centerline of a cylinder | Cylindrical face |
| Plane Intersection | Axis at the intersection of two planes | Two non-parallel planes |
### Points (5 modes)
| Mode | Description | Input |
|------|-------------|-------|
| At Vertex | Point at a vertex location | Vertex |
| XYZ Coordinates | Point at explicit coordinates | x, y, z (mm) |
| On Edge | Point at a location along an edge | Edge + parameter (0.01.0) |
| Face Center | Point at the center of mass of a face | Face |
| Circle Center | Point at the center of a circular or arc edge | Circular edge |
## PartDesign injection
ztools registers a `_ZToolsPartDesignManipulator` that hooks into the PartDesign workbench at startup. This injects the following commands into PartDesign's toolbars and menus:
| PartDesign toolbar | Injected command |
|--------------------|-----------------|
| Part Design Helper Features | `ZTools_DatumCreator`, `ZTools_DatumManager` |
| Part Design Modeling Features | `ZTools_EnhancedPocket` |
| Part Design Transformation Features | `ZTools_RotatedLinearPattern` |
The manipulator is registered in `InitGui.py` when the Create bootstrap module loads addon workbenches.
## Directory structure
```
mods/ztools/
├── ztools/ztools/
│ ├── InitGui.py # Workbench registration + manipulator
│ ├── Init.py # Console initialization
│ ├── commands/
│ │ ├── datum_commands.py # DatumCreator + DatumManager
│ │ ├── datum_viewprovider.py # ViewProvider + edit panel
│ │ ├── pocket_commands.py # EnhancedPocket + FlippedPocket
│ │ ├── pattern_commands.py # RotatedLinearPattern
│ │ ├── assembly_pattern_commands.py # Linear + Polar assembly patterns
│ │ └── spreadsheet_commands.py # 9 formatting commands
│ ├── datums/
│ │ └── core.py # 16 datum creation functions
│ └── resources/ # Icons and theme
└── CatppuccinMocha/ # Theme preference pack
```
## Internal properties
ztools stores metadata on feature objects using these properties (preserved for backward compatibility):
| Property | Purpose |
|----------|---------|
| `ZTools_Type` | Feature type identifier |
| `ZTools_Params` | JSON creation parameters |
| `ZTools_SourceRefs` | JSON source geometry references |
## Known gaps
- Datum Manager is a stub — full implementation planned for Q1 2026
- Datum parameter changes don't recalculate from source geometry yet
- Enhanced Pocket taper angle is disabled for flipped pockets
## Further reading
- `mods/ztools/KINDRED_INTEGRATION.md` — integration architecture and migration options
- `mods/ztools/ROADMAP.md` — phased development plan (Q1Q4 2026)