Metadata-Version: 2.4
Name: caid
Version: 0.2.0
Summary: Agent-friendly OCCT abstraction layer with validated geometry operations
Author: Adam Steen
Author-email: "Claude (Anthropic)" <noreply@anthropic.com>
License-Expression: MIT
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: cadquery-ocp>=7.7
Requires-Dist: trimesh>=4.4
Requires-Dist: pyrender>=0.1.45
Requires-Dist: Pillow>=10.0
Requires-Dist: numpy>=1.26
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-cov>=5.0; extra == "dev"
Provides-Extra: parametric
Requires-Dist: planegcs<1,>=0.8; extra == "parametric"
Dynamic: license-file

# CAiD

An agent-friendly CAD engine built directly on [OpenCASCADE](https://dev.opencascade.org/) through the [cadquery-ocp](https://pypi.org/project/cadquery-ocp/) bindings. CAiD combines a validated stateless geometry API with a persistent semantic document layer for parametric parts and assemblies.

CAiD talks directly to OCCT through OCP — no CadQuery dependency and no FreeCAD application/runtime dependency.

## Install

```bash
python -m venv .venv
source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install caid
```

CAiD 0.2 requires Python 3.12 or newer.

The `cadquery-ocp` wheel is pulled in automatically. Sketch constraint solving is optional:

```bash
pip install "caid[parametric]"
```

The current default sketch adapter uses PlaneGCS and therefore requires Python 3.12+.

## Quick Example

```python
import caid

box = caid.box(40, 30, 10)
print(box.ok)
print(box.volume_after)  # 12000.0

with_hole = caid.add_hole(box, radius=2.7, depth=10)
filleted = caid.fillet(with_hole, radius=1.5, edge_selector=">Z")
caid.to_step(filleted, "bracket.step")
```

## Developer semantic proof programs

The executable [`examples/`](examples/) directory is intentionally **not the product gallery**. These are compact engine-level programs for developers reviewing CAiD's semantics and failure behavior.

| Program | What it proves |
|---|---|
| [`persistent_associativity.py`](examples/persistent_associativity.py) | A persistent top-face reference, datum, and attached sketch follow a body-height revision while retaining the same semantic UUIDs. |
| [`fail_closed_topology.py`](examples/fail_closed_topology.py) | When a shell removes a referenced design face, downstream geometry fails with lost provenance instead of silently rebinding to another face. |
| [`four_bar_ondsel.py`](examples/four_bar_ondsel.py) | A closed kinematic loop explicitly escalates from the deterministic tree solver to the optional nonlinear Ondsel backend and is verified after solving. |

For recognizable engineering examples — mounting brackets, electronics enclosures, manufacturing plates, assemblies, and checked AI revisions — see the [caid-mcp engineering showcase](https://github.com/dreliq9/caid-mcp/tree/main/examples). That MCP surface is the primary product interface for headless AI CAD.

## Architecture

```text
AI / application clients
        ↓
CAiD semantic documents
        ├── CaidDocument        parametric parts
        └── AssemblyDocument    assemblies / mechanisms
        ↓
feature + reference semantics
        ├── parameters / configurations / history
        ├── persistent face & edge provenance
        ├── sketch definitions
        └── mate connectors / joints
        ↓
replaceable numerical services
        ├── SketchSolverProtocol
        │      └── PlaneGCSSolver (default adapter)
        └── AssemblySolverProtocol
               └── TreeAssemblySolver
        ↓
OCP / OpenCASCADE
```

The **semantic document is the source of truth**. B-Reps, solver runtime IDs, and numerical backend state are rebuild products or runtime infrastructure.

### Solver boundaries

CAiD deliberately does not make third-party solver data models part of its file format.

For sketches:

```text
SketchDefinition
      ↓ stable CAiD entity/constraint IDs
SketchSolverProtocol
      ↓
PlaneGCSSolver or another backend
      ↓ stable CAiD-ID SketchSolveReport
```

`SketchDefinition` owns entities, constraints, expressions, contours, stable IDs, and persistence. `PlaneGCSSolver` owns only the numerical solve. A custom backend can be injected directly:

```python
report = definition.solve(parameters, solver=my_solver)
```

or for an entire document rebuild:

```python
doc = caid.CaidDocument("part", sketch_solver=my_solver)
```

The runtime solver is intentionally **not serialized and does not affect the document fingerprint**. A saved `.caid.json` model is therefore not a PlaneGCS document; it is a CAiD document that can be solved by any compatible `SketchSolverProtocol` implementation.

Assemblies follow the same principle through `AssemblySolverProtocol`. The built-in tree solver handles deterministic acyclic joint graphs and explicitly escalates closed loops instead of inventing a traversal-order solution.

This architecture means CAiD may use engines that originated in or are maintained by the FreeCAD ecosystem without becoming “FreeCAD without a GUI.” FreeCAD is useful prior art; CAiD's document model, feature graph, topology semantics, assembly model, and persistence remain independent.

## Key Concepts

### ForgeResult

Every stateless geometry operation returns a `ForgeResult` instead of silently trusting an OCCT operation:

```python
result = caid.box(10, 20, 30)
result.ok
result.shape
result.valid
result.volume_before
result.volume_after
result.surface_area
result.diagnostics
result.unwrap()
```

### Stateless geometry API

Pass shapes in and get validated results out:

```python
a = caid.box(10, 10, 10)
b = caid.cylinder(3, 20)
cut = caid.boolean_cut(a, b)
```

### Parametric part documents

`CaidDocument` provides persistent semantic modeling above the stateless geometry layer. Current capabilities include:

- named parameters and safe expressions;
- stable-ID general sketches and constraints;
- arbitrary reference-plane placement;
- extrude, cut-extrude, revolve, holes;
- persistent face/edge references with OCCT history + TNaming support;
- fillet, chamfer, shell, draft, mirror;
- linear and circular patterns;
- named configurations;
- dependency-safe feature history, suppression, and rollback;
- semantic save/open and deterministic fingerprints.

Example:

```python
import caid

sketch = caid.SketchDefinition("Profile")
p0 = sketch.add_point(0, 0, fixed=True)
p1 = sketch.add_point("Width", 0)
p2 = sketch.add_point("Width", "Height")
p3 = sketch.add_point(0, "Height")
l0 = sketch.add_line(p0, p1)
l1 = sketch.add_line(p1, p2)
l2 = sketch.add_line(p2, p3)
l3 = sketch.add_line(p3, p0)
sketch.constrain("horizontal", l0)
sketch.constrain("horizontal", l2)
sketch.constrain("vertical", l1)
sketch.constrain("vertical", l3)
sketch.constrain("distance", p0, p1, value="Width")
sketch.constrain("distance", p1, p2, value="Height")
sketch.add_contour(l0, l1, l2, l3)

doc = caid.CaidDocument("bracket")
doc.add_parameter("Width", 40)
doc.add_parameter("Height", 30)
doc.add_parameter("Depth", 10)
profile = doc.add_feature(caid.GeneralSketchFeature("Profile", sketch))
body = doc.add_feature(caid.ExtrudeFeature("Body", profile.id, "Depth"))
assert doc.rebuild().ok

doc.set_parameter("Width", 60)
assert doc.rebuild().ok
doc.save("bracket.caid.json")
```

### Persistent topology

Persistent geometry references use stable CAiD UUIDs and feature-owned design provenance. Current operator history is checked before TNaming so a prior binding cannot hide a later face/edge split. Ambiguous or lost design entities fail closed rather than silently selecting a geometrically convenient replacement.

### Assemblies

`AssemblyDocument` embeds reusable semantic part definitions and stores stable component instances, rigid poses, mate connectors, grounded state, typed joints, BOM data, and interference checks.

The built-in `TreeAssemblySolver` supports fixed, revolute, slider, and cylindrical joints on acyclic graphs. Floating components report `underconstrained`; closed joint loops report `needs_nonlinear_solver` so a stronger backend can be introduced through the same solver protocol.

## Output Directory

By default, exports go to `~/cadquery-output/` for backward compatibility.

## Development

```bash
pip install -e ".[dev,parametric]"
pytest -q
```

## License

MIT — see [LICENSE](LICENSE).
