# A deep dive into Nurb

> Nurb turns a coding agent into a CAD partner. Learn how Python parts, OCCT solids, live checks, measurements, and 3MF export fit together.

Author: [Flavio Copes](https://flaviocopes.com/about/) | Published: 2026-08-23 | Topics: [AI](https://flaviocopes.com/tags/ai/) | Canonical: https://flaviocopes.com/nurb/

I found [Nurb](https://nurb.dev/) through [a post by Scott Tolinski](https://x.com/stolinski/status/2090829581561503847).

Nurb was not the main topic, but the name sent me down a rabbit hole.

[Josh Pigford](https://x.com/Shpigford) created it.

The idea is simple.

You describe a physical part. Your coding agent models it. Nurb checks it, shows it in a live viewer, and gives you a file to print.

This sounds like another text-to-3D generator.

It is not.

Nurb does not ask a model to produce a mysterious mesh. It gives an existing coding agent a complete CAD workflow.

The agent writes a parametric part as Python code. Nurb builds it with a real CAD kernel, runs checks against the solid, and keeps you in the loop through a browser viewer.

That difference is what makes Nurb interesting.

## What Nurb is

Nurb describes itself as **agentic CAD for 3D printing**.

You keep using the AI agent you already have. Nurb adds the specialized tools and instructions that let the agent design printable parts.

The current workflow looks like this:

```mermaid
flowchart LR
  U["You describe a part"] --> A["Coding agent"]
  A --> P["Python @part function"]
  P --> K["build123d and OCCT"]
  K --> V["Live viewer"]
  K --> C["Printability checks"]
  V --> U
  C --> A
  V --> E["3MF export"]
  E --> R["3D printer"]
```

You still make the decisions.

The agent handles the CAD operations. Nurb gives it a vocabulary, a design doctrine, measurements, tests, and feedback.

The viewer lets you orbit the part, cut it open with a section plane, and change dimensions with sliders.

When the result looks right and the checks are clean, you export it.

## A part is a Python function

Nurb parts are Python functions decorated with `@part`.

Here is the shape of a part:

```python
from nurb import *

@part
def hose_adapter(vac_end=57.6, tool_end=35.0, wall=2.4):
    ...
```

The function body uses [build123d](https://build123d.readthedocs.io/) to create the geometry.

The keyword defaults are also the part parameters.

Nurb reads them to create the viewer controls. A floating-point value becomes a continuous dimension. An integer becomes a stepped control. A boolean becomes a switch.

There is no second settings schema to maintain.

Change `wall=2.4` in the function and the default in the viewer changes too. Move the slider in the viewer and click `write`, and Nurb writes the chosen value back to the function.

This is a small design decision with a big effect.

The code, viewer, command line, variants, and tests all describe the same part.

## Nurb creates real CAD solids

Many AI 3D tools generate meshes.

A mesh is a surface made of triangles. It can look right, but editing one dimension later is difficult. A hole is not a hole with a diameter. It is a collection of triangles that happen to form a hole.

Nurb works differently.

The Python function builds a **B-rep solid** using build123d and the [Open CASCADE Technology](https://dev.opencascade.org/) kernel.

A B-rep keeps the mathematical boundaries of the part. Faces, edges, holes, fillets, and chamfers remain CAD geometry.

This gives Nurb a few important properties:

- dimensions remain parameters
- chamfers and fillets are real operations
- checks can inspect the exact solid
- STEP export keeps editable CAD geometry
- the same part can produce several variants

Nurb still creates a triangle representation for the browser and printer formats. But that happens after the part exists as a solid.

The mesh is an output, not the source of truth.

## The live viewer closes the loop

CAD work is visual.

An agent can write valid Python and still produce the wrong shape. It needs feedback, and so do we.

`nurb dev` starts a long-running process that watches the project files. The first build can be slow because the CAD kernel must load. After that, most edits appear in the browser in under a second.

The server rebuilds the part, turns it into a GLB scene, and pushes it to the viewer over a WebSocket.

The camera does not reset after every update. You can keep looking at the same corner while the agent changes it.

The viewer also shows the parameters, dimensions, check findings, variants, and export controls.

This changes the conversation.

Instead of asking an agent to work for ten minutes and reveal a final model, you can watch the part evolve. If the basic shape is wrong, you can correct it before the agent polishes the wrong design.

## The agent skill is part of the product

The interesting part of Nurb is not only the CAD library.

It ships with an [Agent Skill](https://github.com/Shpigford/nurb/tree/main/skills/nurb) that teaches a coding agent how to use the tool.

The skill tells the agent to:

- start the live viewer early
- read Nurb's design doctrine
- ask for missing measurements
- build a rough shape first
- inspect the exact faces behind a warning
- run printability checks after changes
- verify the result before export
- keep the user looking at the current part

This is a good example of what an Agent Skill should do.

It does not try to put all of CAD inside a prompt. It gives the agent a repeatable workflow and sends detailed knowledge to the tool when needed.

If you want to build this kind of workflow for your own tools, my [free AI Agent Skills course](https://flaviocopes.com/courses/ai-agent-skills/) explains discovery, instructions, scripts, resources, safety boundaries, and evaluations.

## Measurements are treated as data

The hardest part of a one-off printed adapter is often not the geometry.

It is getting the dimensions right.

An agent can invent a plausible hose diameter. The part can build, pass every geometry check, and still not fit the hose.

Nurb stores real-world measurements in `measurements.toml`:

```toml
[shop_vac_hose]
value = 57.6
unit = "mm"
how = "measured with calipers"
```

The part reads the value with `measured('shop_vac_hose')`.

If the measurement is missing, Nurb raises an error instead of letting the agent guess.

You can mark a value as provisional when you have to estimate it. The part still builds, but `nurb check` keeps reporting that the measurement needs confirmation.

This is one of my favorite ideas in the project.

The system cannot guarantee that a number is correct. It can make sure a guess does not quietly turn into a fact.

## Cards give the next agent context

Each part can have a Markdown card beside its Python file.

The card records what the part is, why it exists, important design decisions, and what was tried and rejected.

Nurb also writes an automatic block with facts it can measure from the build, including:

- dimensions
- volume
- solid and face counts
- check results
- variant results

This gives the agent memory across sessions.

The `## Don't` section is especially useful. If a chamfer was removed because it broke a mating surface, the next agent sees that decision instead of adding it again.

`nurb diff` compares the current solid with the facts stored on the card. A change that quietly removes faces or alters the volume becomes visible even if the part still looks fine from one angle.

## The checks turn print physics into feedback

`nurb check` runs rules against the built solid.

The current rules cover problems such as:

- multiple loose solids
- unsupported overhangs and floating regions
- blind-hole ceilings
- walls that are too thin
- tiny sliver faces
- unstable parts
- large first layers that may warp
- pins that are too thin
- parts outside the printer's build volume

Findings include coordinates and point at the relevant geometry in the viewer.

The command reports findings without blocking the iteration loop by default. Use strict mode when a clean result should be required:

```bash
nurb check --strict
```

This also makes the checks useful in CI.

The checks are valuable, but they are not proof that a print will succeed.

For example, the minimum-wall rule samples the solid. It can miss a narrow pinch that no probe reaches. A clean result means Nurb found no thin wall, not that every possible wall was mathematically proven thick enough.

That kind of honest limitation makes the checks more useful.

## Nurb goes beyond geometry

Nurb connects the model to the rest of the printing workflow.

You can name your printer and material in `printer.toml`. The checks then know the build volume, nozzle size, and how strongly the material tends to warp.

`nurb slice` uses an installed OrcaSlicer or Bambu Studio to estimate print time and filament weight.

`nurb stress` runs an approximate voxel simulation. It shows where a load concentrates, how much the part may sag, and the margin before failure.

I would treat this as comparative feedback, not an engineering certification. It can help compare two designs. It cannot prove that a safety-critical part will hold.

Nurb can also inspect phone scans and downloaded meshes. A scan provides reference geometry. The agent then rebuilds the useful shape as a parametric part instead of pretending that a triangle mesh contains editable dimensions.

For multi-part designs, assemblies can place parts together and sweep a hinge through its motion. A box and lid may each print correctly but collide when opened. Assembly checks catch a different class of failure.

## Install Nurb

The easiest path on macOS is the [Nurb app](https://nurb.dev/).

It puts the project, agent chat, and viewer in one window. The current downloads support Apple silicon and Intel Macs.

You can also install the command-line tool:

```bash
curl -fsSL https://nurb.dev/install.sh | sh
```

The installer adds `uv` when needed, installs Nurb, and installs the Agent Skill.

If you prefer to manage each step yourself, install the Python package first:

```bash
uv tool install nurb
```

Then install the skill:

```bash
npx skills add shpigford/nurb --skill nurb
```

A Nurb project is any directory containing a `parts/` folder. There is no project initialization format to learn.

Open your agent in that directory and describe a small part:

> Make an adapter that connects my shop vac hose to the dust port on my table saw.

The agent should create the project, start `nurb dev`, show you the viewer URL, and begin with a rough part you can judge.

## How I would use Nurb

I would start with a boring physical problem.

A cable guide, a small bracket, a holder, or an adapter is ideal. The dimensions are understandable, the part is cheap to print, and failure is not dangerous.

My workflow would be:

1. Measure every surface that must fit.
2. Ask the agent for a rough parametric part.
3. Inspect it in the live viewer.
4. Adjust free dimensions with sliders.
5. Print a small fit coupon when a mating profile is uncertain.
6. Run the strict checks.
7. Compare print time and material use.
8. Export the 3MF and make one test print.

I would keep the first design simple.

If a part needs several moving pieces, tight tolerances, or a complex load path, I would build confidence one interface at a time.

I would not use Nurb as the only validation for something that can hurt a person when it fails. I would also not choose it for character models, organic sculpture, or other work where a mesh sculpting tool is the natural fit.

Nurb looks strongest for functional FDM parts: the little physical objects that solve one specific problem.

## The current limits

Nurb is moving very quickly and the package is marked as alpha.

Commands, checks, and the application can change between the time I write this and the time you try it.

The project also lists a few missing pieces:

- there is no hosted configurator
- the viewer has no measurement tools yet
- some checks use sampling and can miss a problem
- real-world fit still depends on real measurements

The modelling, checks, viewer, and exports run locally. Your AI agent may still use an online model, depending on the agent and subscription you choose.

The [source is public on GitHub](https://github.com/Shpigford/nurb), but the license needs a precise description.

Nurb uses the [FSL-1.1-MIT license](https://github.com/Shpigford/nurb/blob/main/LICENSE). It is source-available and blocks competing products for two years. Each release then converts to MIT after its two-year period.

That is not the same as a conventional open source license from day one.

## Why I find Nurb interesting

Nurb puts a conversational interface on top of CAD, but it does not make the conversation the source of truth.

The source of truth is a Python function, a measurements file, a card, and a set of checks.

The agent can make changes quickly because the important constraints live outside its memory.

And the human stays in the right place: judging the object, correcting the intent, and deciding when it is ready to print.

This is the kind of AI tool I like.

It does not hide the real system. It gives an agent a better way to operate it.
