b123d-print 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- b123d_print-0.1.0/LICENSE +21 -0
- b123d_print-0.1.0/PKG-INFO +501 -0
- b123d_print-0.1.0/README.md +485 -0
- b123d_print-0.1.0/THIRD_PARTY.md +37 -0
- b123d_print-0.1.0/pyproject.toml +51 -0
- b123d_print-0.1.0/pyproject.toml.orig +34 -0
- b123d_print-0.1.0/src/b123d_print/__init__.py +16 -0
- b123d_print-0.1.0/src/b123d_print/checks.py +391 -0
- b123d_print-0.1.0/src/b123d_print/cli.py +251 -0
- b123d_print-0.1.0/src/b123d_print/config.py +191 -0
- b123d_print-0.1.0/src/b123d_print/data/AGENTS.md +110 -0
- b123d_print-0.1.0/src/b123d_print/data/b123d-print.toml +13 -0
- b123d_print-0.1.0/src/b123d_print/data/materials/abs.toml +2 -0
- b123d_print-0.1.0/src/b123d_print/data/materials/asa.toml +2 -0
- b123d_print-0.1.0/src/b123d_print/data/materials/petg.toml +2 -0
- b123d_print-0.1.0/src/b123d_print/data/materials/pla.toml +2 -0
- b123d_print-0.1.0/src/b123d_print/data/materials/tpu.toml +2 -0
- b123d_print-0.1.0/src/b123d_print/data/part_template.py +63 -0
- b123d_print-0.1.0/src/b123d_print/data/printers_orca.json +3652 -0
- b123d_print-0.1.0/src/b123d_print/examples/esp_ir_blaster/esp_ir_blaster.py +361 -0
- b123d_print-0.1.0/src/b123d_print/examples/hole_coupon/hole_coupon.py +78 -0
- b123d_print-0.1.0/src/b123d_print/examples/plate_2gang_to_1gang/plate_2gang_to_1gang.py +252 -0
- b123d_print-0.1.0/src/b123d_print/examples/testblock/testblock.py +48 -0
- b123d_print-0.1.0/src/b123d_print/examples/tuya_motion_sensor_outdoor_case/tuya_motion_sensor_outdoor_case.py +393 -0
- b123d_print-0.1.0/src/b123d_print/mcp_server.py +364 -0
- b123d_print-0.1.0/src/b123d_print/profiles.py +203 -0
- b123d_print-0.1.0/src/b123d_print/project.py +208 -0
- b123d_print-0.1.0/src/b123d_print/py.typed +0 -0
- b123d_print-0.1.0/src/b123d_print/render.py +226 -0
- b123d_print-0.1.0/src/b123d_print/sandbox.py +163 -0
- b123d_print-0.1.0/src/b123d_print/worker.py +220 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 KD5RYN and contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: b123d-print
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Design, check and export 3D-printable parts with build123d, from any LLM via MCP
|
|
5
|
+
Keywords: cad,3d-printing,build123d,mcp,llm
|
|
6
|
+
Author: KD5RYN, b123d-print contributors
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
License-File: THIRD_PARTY.md
|
|
10
|
+
Requires-Dist: build123d==0.13.0
|
|
11
|
+
Requires-Dist: matplotlib==3.11.2
|
|
12
|
+
Requires-Dist: mcp==2.3.0
|
|
13
|
+
Requires-Dist: numpy==2.5.4
|
|
14
|
+
Requires-Python: ==3.12.*
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
# b123d-print
|
|
18
|
+
|
|
19
|
+
[](https://github.com/KD5RYN/b123d-print/actions/workflows/ci.yml)
|
|
20
|
+
[](LICENSE)
|
|
21
|
+
|
|
22
|
+
Design 3D-printable parts with an AI assistant — any assistant. You describe a part (photos,
|
|
23
|
+
caliper readings); the model writes a [build123d](https://github.com/gumyr/build123d) Python
|
|
24
|
+
script; b123d-print builds it in a sandbox, renders it, cuts cross-sections, runs print checks,
|
|
25
|
+
and exports the formats you pick: STEP, STL, 3MF, PNG.
|
|
26
|
+
|
|
27
|
+
| | |
|
|
28
|
+
| --- | --- |
|
|
29
|
+
|  |  |
|
|
30
|
+
| *Two-part box for an IR transceiver board, with the board stand-ins* | *Section through the LED: lid cone, board, clearances* |
|
|
31
|
+
|  |  |
|
|
32
|
+
| *Outdoor sensor case: dovetail back plate + support-free cover* | *Wall plate: section just past the face, where the wall check looks* |
|
|
33
|
+
|
|
34
|
+
**Scope: parts for FDM 3D printing, nothing else.** Everything is built around a printed part:
|
|
35
|
+
print orientation with the bed at Z=0, hole compensation, mating clearance, and overhang,
|
|
36
|
+
wall-thickness and overlap checks. It is not a general CAD framework.
|
|
37
|
+
|
|
38
|
+
## What's in it
|
|
39
|
+
|
|
40
|
+
- **`b123d-print` package + CLI** — export, 6-view renders, colored multi-part cross-sections,
|
|
41
|
+
and print checks: **overlap** between mating parts, **overhang** in print orientation, **wall
|
|
42
|
+
thickness** around cuts, **probes** ("is the roof closed?").
|
|
43
|
+
- **`b123d-print-mcp`** — an [MCP](https://modelcontextprotocol.io) server, so it works from
|
|
44
|
+
Claude Desktop, Claude Code, Gemini CLI, Cursor, VS Code, Codex and other MCP clients. Part
|
|
45
|
+
scripts are model-written code: they run in a sandbox with a timeout and no network.
|
|
46
|
+
- **The workflow, model-neutral** — MCP prompts plus an [`AGENTS.md`](AGENTS.md) any agent can
|
|
47
|
+
read. The rules come from real prints; one exists because a part broke through a 0.05 mm skin
|
|
48
|
+
that no render showed.
|
|
49
|
+
- **Examples** — four parts designed this way and printed, plus a hole calibration coupon, in
|
|
50
|
+
[`src/b123d_print/examples/`](src/b123d_print/examples/).
|
|
51
|
+
|
|
52
|
+
## Quick start
|
|
53
|
+
|
|
54
|
+
1. Install [uv](https://docs.astral.sh/uv/getting-started/installation/). It fetches Python 3.12
|
|
55
|
+
and every pinned dependency for you.
|
|
56
|
+
2. Add the server to your MCP client — Claude Desktop shown, [others below](#connect-your-mcp-client):
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"mcpServers": {
|
|
61
|
+
"b123d-print": {
|
|
62
|
+
"command": "uvx",
|
|
63
|
+
"args": ["--from", "git+https://github.com/KD5RYN/b123d-print", "b123d-print-mcp",
|
|
64
|
+
"--workspace", "/Users/you/parts"]
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
3. Restart the client and ask: *"Design a 40 mm round spacer, 10 mm tall, with an M3 hole."*
|
|
71
|
+
Files land in `/Users/you/parts/parts/<name>/out/`.
|
|
72
|
+
|
|
73
|
+
The first start downloads a few hundred MB (mostly OpenCascade, the geometry kernel) and can
|
|
74
|
+
take a few minutes; later starts are fast. See [Troubleshooting](#troubleshooting) if your
|
|
75
|
+
client gives up waiting.
|
|
76
|
+
|
|
77
|
+
> **Images:** `render_preview` and `section` return PNG images. The model can only check its own
|
|
78
|
+
> work if your client passes tool-result images to the model. Claude Desktop and Claude Code do;
|
|
79
|
+
> check your client's docs for others. Without it the checks still run, but the model designs
|
|
80
|
+
> blind — look at the PNGs in `out/` yourself.
|
|
81
|
+
|
|
82
|
+
## Ways to use it
|
|
83
|
+
|
|
84
|
+
| Method | When | Sandbox |
|
|
85
|
+
| --- | --- | --- |
|
|
86
|
+
| **MCP server via `uvx`** | any MCP client; the normal way | yes (macOS; Linux with bubblewrap) |
|
|
87
|
+
| **MCP server in Docker** | strongest isolation, or Windows | the container |
|
|
88
|
+
| **Claude Code plugin** | Claude Code; adds a skill that points at the workflow | yes |
|
|
89
|
+
| **CLI / Python** | agents that run shell commands, or by hand | no — runs your own scripts |
|
|
90
|
+
|
|
91
|
+
### Connect your MCP client
|
|
92
|
+
|
|
93
|
+
Every client runs the same command:
|
|
94
|
+
`uvx --from git+https://github.com/KD5RYN/b123d-print b123d-print-mcp --workspace <folder>`.
|
|
95
|
+
The **workspace** is the folder that holds your parts (`parts/<name>/<name>.py`); it is created
|
|
96
|
+
if missing. Without `--workspace` the server uses `$B123D_PRINT_WORKSPACE`, else the folder the
|
|
97
|
+
client starts it in.
|
|
98
|
+
|
|
99
|
+
<details>
|
|
100
|
+
<summary><b>Claude Desktop</b></summary>
|
|
101
|
+
|
|
102
|
+
Settings → Developer → Edit Config (`claude_desktop_config.json`): the block in
|
|
103
|
+
[Quick start](#quick-start). Always pass `--workspace`. If the server fails with "uvx not
|
|
104
|
+
found", use the full path from `which uvx` as `command` (desktop apps don't see your shell's
|
|
105
|
+
`PATH`).
|
|
106
|
+
</details>
|
|
107
|
+
|
|
108
|
+
<details>
|
|
109
|
+
<summary><b>Claude Code</b></summary>
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
claude mcp add b123d-print -- uvx --from git+https://github.com/KD5RYN/b123d-print b123d-print-mcp --workspace ~/parts
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Or the plugin (MCP server + skill; uses the project folder as workspace), inside Claude Code:
|
|
116
|
+
|
|
117
|
+
```text
|
|
118
|
+
/plugin marketplace add KD5RYN/b123d-print
|
|
119
|
+
/plugin install b123d-print@b123d-print
|
|
120
|
+
```
|
|
121
|
+
</details>
|
|
122
|
+
|
|
123
|
+
<details>
|
|
124
|
+
<summary><b>Gemini CLI</b></summary>
|
|
125
|
+
|
|
126
|
+
`~/.gemini/settings.json` (or `.gemini/settings.json` in a project):
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"mcpServers": {
|
|
131
|
+
"b123d-print": {
|
|
132
|
+
"command": "uvx",
|
|
133
|
+
"args": ["--from", "git+https://github.com/KD5RYN/b123d-print", "b123d-print-mcp", "--workspace", "/Users/you/parts"]
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
</details>
|
|
139
|
+
|
|
140
|
+
<details>
|
|
141
|
+
<summary><b>Cursor</b></summary>
|
|
142
|
+
|
|
143
|
+
`~/.cursor/mcp.json`, or `.cursor/mcp.json` in a project: the same `mcpServers` block as for
|
|
144
|
+
Gemini CLI.
|
|
145
|
+
</details>
|
|
146
|
+
|
|
147
|
+
<details>
|
|
148
|
+
<summary><b>VS Code (Copilot agent mode)</b></summary>
|
|
149
|
+
|
|
150
|
+
`.vscode/mcp.json`:
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"servers": {
|
|
155
|
+
"b123d-print": {
|
|
156
|
+
"type": "stdio",
|
|
157
|
+
"command": "uvx",
|
|
158
|
+
"args": ["--from", "git+https://github.com/KD5RYN/b123d-print", "b123d-print-mcp", "--workspace", "${workspaceFolder}"]
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
</details>
|
|
164
|
+
|
|
165
|
+
<details>
|
|
166
|
+
<summary><b>Codex CLI</b></summary>
|
|
167
|
+
|
|
168
|
+
`~/.codex/config.toml`:
|
|
169
|
+
|
|
170
|
+
```toml
|
|
171
|
+
[mcp_servers.b123d-print]
|
|
172
|
+
command = "uvx"
|
|
173
|
+
args = ["--from", "git+https://github.com/KD5RYN/b123d-print", "b123d-print-mcp", "--workspace", "/Users/you/parts"]
|
|
174
|
+
```
|
|
175
|
+
</details>
|
|
176
|
+
|
|
177
|
+
<details>
|
|
178
|
+
<summary><b>Other clients</b></summary>
|
|
179
|
+
|
|
180
|
+
Any client that can start a stdio MCP server: command `uvx`, arguments as above. To pin a
|
|
181
|
+
version, use `git+https://github.com/KD5RYN/b123d-print@v0.1.0` once releases exist.
|
|
182
|
+
</details>
|
|
183
|
+
|
|
184
|
+
### Docker
|
|
185
|
+
|
|
186
|
+
The container is the sandbox: no network, and it sees only the folder you mount.
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
git clone https://github.com/KD5RYN/b123d-print && cd b123d-print
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
docker build -t b123d-print-mcp .
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Then point your client at Docker instead of `uvx` (Claude Desktop shown):
|
|
197
|
+
|
|
198
|
+
```json
|
|
199
|
+
{
|
|
200
|
+
"mcpServers": {
|
|
201
|
+
"b123d-print": {
|
|
202
|
+
"command": "docker",
|
|
203
|
+
"args": ["run", "-i", "--rm", "--network", "none",
|
|
204
|
+
"-v", "/Users/you/parts:/work", "b123d-print-mcp"]
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
- `-i` is required (MCP talks over stdin/stdout); `--rm` removes the container afterwards.
|
|
211
|
+
- Your parts and exports appear in the mounted folder (`/Users/you/parts` above). Settings
|
|
212
|
+
(printer, hole compensation) are kept there too, in `.config/b123d-print/`, since the
|
|
213
|
+
container has no lasting home folder.
|
|
214
|
+
- On Linux, add `"--user", "1000:1000"` (your `id -u`:`id -g`) so exported files belong to you.
|
|
215
|
+
- Released images will also be on GitHub's registry as `ghcr.io/kd5ryn/b123d-print-mcp`.
|
|
216
|
+
|
|
217
|
+
### CLI and Python (no MCP)
|
|
218
|
+
|
|
219
|
+
For agents that run shell commands, and for you:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
uv tool install git+https://github.com/KD5RYN/b123d-print
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
b123d-print init ~/parts && cd ~/parts
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
b123d-print new bracket
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Edit `parts/bracket/bracket.py` (or let your agent do it), then:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
b123d-print build bracket --formats 3mf,png
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
b123d-print check
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
| Command | Does |
|
|
244
|
+
| --- | --- |
|
|
245
|
+
| `init [dir]` | create a workspace: `b123d-print.toml`, `AGENTS.md`, `parts/` |
|
|
246
|
+
| `new <name> [--from <example>]` | scaffold a part from the template or a bundled example |
|
|
247
|
+
| `build [parts] [--variant v] [--formats f]` | export + section views, report sizes |
|
|
248
|
+
| `check [parts] [-v] [--json]` | run the checks; exit code 1 on any failure |
|
|
249
|
+
| `examples` / `list` / `config` | bundled examples / parts in the workspace / settings in effect |
|
|
250
|
+
|
|
251
|
+
`AGENTS.md` (written by `init`) carries the workflow for agents that read it, such as Codex and
|
|
252
|
+
Cursor; for Claude Code put `@AGENTS.md` in `CLAUDE.md`. Running a part script directly also
|
|
253
|
+
works: `uv run parts/bracket/bracket.py`. The CLI does **not** sandbox: it runs your scripts
|
|
254
|
+
like any Python.
|
|
255
|
+
|
|
256
|
+
## How a session goes
|
|
257
|
+
|
|
258
|
+
Start with one of the MCP prompts where your client supports them —
|
|
259
|
+
**`design_part_from_photos`**, **`modify_part`**, **`verify_part`**, **`calibrate_hole_comp`** —
|
|
260
|
+
or just ask; the server's instructions and the `b123d-print://guide` resource carry the same
|
|
261
|
+
rules. An illustrative, shortened exchange:
|
|
262
|
+
|
|
263
|
+
> **You:** A case for this PIR sensor, mounted on a wall outside. *(photos with calipers)*
|
|
264
|
+
>
|
|
265
|
+
> **Model:** Dimensions I read: body 69.6 × 24.5 × 19.1 (photo 2, calipers), dome Ø18.6
|
|
266
|
+
> (photo 3), dome center about 35.5 from the bottom (estimate). Nothing shows how far the dome
|
|
267
|
+
> sticks out. Please confirm or correct before I model.
|
|
268
|
+
>
|
|
269
|
+
> **You:** Dome sticks out 8. The rest is right.
|
|
270
|
+
>
|
|
271
|
+
> **Model:** *(new_part, write_part, build_part, render_preview, three sections, check; fixes a
|
|
272
|
+
> thin wall the check found, checks again)* Done: 35.1 × 38.8 × 76.6 mm, valid. The sensor gets
|
|
273
|
+
> 0.6 mm per side, the dovetail 0.2 per face. Prints on its floor without supports (one flat
|
|
274
|
+
> bridge over the groove). Exported 3MF and PNG.
|
|
275
|
+
|
|
276
|
+
| Tool | What it does |
|
|
277
|
+
| --- | --- |
|
|
278
|
+
| `list_parts` | parts, bundled examples, settings in effect, sandbox in use |
|
|
279
|
+
| `new_part(name, description?, example?)` | scaffold from the template, or copy a bundled example |
|
|
280
|
+
| `read_part` / `write_part` | read / replace the script (syntax-checked before saving) |
|
|
281
|
+
| `build_part(name, variant?)` | run it: bounding box, volume, validity, dimensions, errors |
|
|
282
|
+
| `render_preview(name, variant?, parts?)` | 6-view PNG; `parts="assembly"` shows the fit |
|
|
283
|
+
| `section(name, plane, at, ...)` | colored cross-section PNG on `XY`, `XZ` or `YZ` |
|
|
284
|
+
| `check(name, variant?)` | validity, overlap, overhang, wall and probe checks |
|
|
285
|
+
| `export(name, variant?, formats?)` | files to `parts/<name>/out/` |
|
|
286
|
+
|
|
287
|
+
## Output formats
|
|
288
|
+
|
|
289
|
+
| File | For |
|
|
290
|
+
| --- | --- |
|
|
291
|
+
| `<name>.py` (always) | the parametric source: change a `Dims` value, rebuild everything |
|
|
292
|
+
| `.step` | editing in other CAD (Fusion, Onshape, FreeCAD, SolidWorks): an exact solid you can push/pull, fillet and cut, without feature history; changes there don't flow back to the script |
|
|
293
|
+
| `.stl` | any slicer |
|
|
294
|
+
| `.3mf` | slicers that read it (Bambu Studio, OrcaSlicer, PrusaSlicer); keeps units |
|
|
295
|
+
| `.png` | 6-view preview, assembly render, section views |
|
|
296
|
+
|
|
297
|
+
Pick them in your config (`formats = ["3mf", "png"]`), per run (`--formats step,3mf`), or with
|
|
298
|
+
`formats=` on the MCP `export` tool. Default: all four.
|
|
299
|
+
|
|
300
|
+
## A part script
|
|
301
|
+
|
|
302
|
+
```python
|
|
303
|
+
from dataclasses import dataclass
|
|
304
|
+
from build123d import Align, Box, Cylinder, Mode, Part
|
|
305
|
+
from b123d_print import View, Wall, hole_comp
|
|
306
|
+
|
|
307
|
+
BED = (Align.CENTER, Align.CENTER, Align.MIN)
|
|
308
|
+
|
|
309
|
+
@dataclass(frozen=True)
|
|
310
|
+
class Dims: # every dimension named, in mm, with its source
|
|
311
|
+
W: float = 30.0 # typed measurement
|
|
312
|
+
H: float = 8.0
|
|
313
|
+
HOLE_D: float = 3.4 # M3 clearance, target printed size
|
|
314
|
+
CBORE_D: float = 6.5
|
|
315
|
+
CBORE_DEPTH: float = 3.0
|
|
316
|
+
HOLE_COMP: float = hole_comp(__file__) # from YOUR config, default 0
|
|
317
|
+
|
|
318
|
+
VARIANTS = {"": {}, "wide": dict(W=40.0)} # overrides only
|
|
319
|
+
|
|
320
|
+
def build(d: Dims) -> Part: # print orientation, bed at Z=0
|
|
321
|
+
p = Box(d.W, d.W, d.H, align=BED)
|
|
322
|
+
p -= Cylinder((d.HOLE_D + d.HOLE_COMP) / 2, 50, mode=Mode.PRIVATE)
|
|
323
|
+
p -= Cylinder((d.CBORE_D + d.HOLE_COMP) / 2, d.CBORE_DEPTH, align=BED, mode=Mode.PRIVATE)
|
|
324
|
+
return p
|
|
325
|
+
|
|
326
|
+
def views(d): # sections saved with every export
|
|
327
|
+
return [View("XZ", 0.0, "through the hole")]
|
|
328
|
+
|
|
329
|
+
def checks(d): # how much material is left around the counterbore?
|
|
330
|
+
return [Wall("", "XY", d.CBORE_DEPTH / 2, near=(0, 0), radius=d.W, label="around the counterbore")]
|
|
331
|
+
|
|
332
|
+
if __name__ == "__main__":
|
|
333
|
+
from b123d_print import run
|
|
334
|
+
run(__file__)
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
Optional `assembly(d)` returns the parts in assembled position plus stand-ins for what they
|
|
338
|
+
mate with (a PCB, a sensor); the overlap check makes sure nothing printed hits them. See
|
|
339
|
+
[`esp_ir_blaster`](src/b123d_print/examples/esp_ir_blaster/esp_ir_blaster.py) and
|
|
340
|
+
[`tuya_motion_sensor_outdoor_case`](src/b123d_print/examples/tuya_motion_sensor_outdoor_case/tuya_motion_sensor_outdoor_case.py).
|
|
341
|
+
The modeling API itself is documented in the [build123d docs](https://build123d.readthedocs.io).
|
|
342
|
+
|
|
343
|
+
## Settings and hole compensation
|
|
344
|
+
|
|
345
|
+
FDM printers print small holes undersize, by an amount that depends on printer, nozzle,
|
|
346
|
+
material and slicer. b123d-print never assumes a value: `hole_comp` defaults to **0**.
|
|
347
|
+
|
|
348
|
+

|
|
349
|
+
|
|
350
|
+
Print the coupon (`new_part("coupon", example="hole_coupon")` over MCP, or
|
|
351
|
+
`b123d-print new coupon --from hole_coupon`), measure each hole, and set the average error:
|
|
352
|
+
|
|
353
|
+
```toml
|
|
354
|
+
# ~/.config/b123d-print/config.toml (`b123d-print config` shows what is in effect)
|
|
355
|
+
[print]
|
|
356
|
+
hole_comp = 0.4 # mm added to hole diameters when cutting
|
|
357
|
+
clearance = 0.2 # default mating gap
|
|
358
|
+
min_wall = 0.8 # Wall checks fail below this unless they set their own limit
|
|
359
|
+
max_overhang = 45 # degrees from vertical
|
|
360
|
+
formats = ["step", "stl", "3mf", "png"]
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
A workspace `b123d-print.toml` overrides the user config; environment variables
|
|
364
|
+
(`B123D_PRINT_HOLE_COMP`, `B123D_PRINT_FORMATS`, ...) override both.
|
|
365
|
+
|
|
366
|
+
## Printer profile (optional)
|
|
367
|
+
|
|
368
|
+
By default b123d-print is in **generic mode**: no printer assumed, 0.8 mm minimum wall, 45°
|
|
369
|
+
overhang limit. If you set your printer, the model also knows its build volume and nozzle:
|
|
370
|
+
|
|
371
|
+
```bash
|
|
372
|
+
b123d-print printer list bambu a1 # search 405 printer models
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
```bash
|
|
376
|
+
b123d-print printer use bambu_lab_a1_mini --material petg
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
- Parts must then fit the build volume in print orientation (`fit` check; it fails otherwise).
|
|
380
|
+
- Minimum wall becomes 2 line widths of your nozzle; material notes (PLA vs PETG vs ASA …) reach
|
|
381
|
+
the model.
|
|
382
|
+
- `b123d-print printer hole-comp 0.4` stores your coupon result for that printer + material.
|
|
383
|
+
- `b123d-print printer use generic` goes back. Over MCP: the `use_printer` tool.
|
|
384
|
+
|
|
385
|
+
Printer dimensions come from [OrcaSlicer](https://github.com/SoftFever/OrcaSlicer)'s printer
|
|
386
|
+
library (facts only; see [THIRD_PARTY.md](THIRD_PARTY.md)). Not listed, or modified? Add your own
|
|
387
|
+
`~/.config/b123d-print/printers/<name>.toml`:
|
|
388
|
+
|
|
389
|
+
```toml
|
|
390
|
+
label = "My Ender 3 with 0.6 nozzle"
|
|
391
|
+
bed_x = 220
|
|
392
|
+
bed_y = 220
|
|
393
|
+
height = 250
|
|
394
|
+
nozzle = 0.6
|
|
395
|
+
# round_bed = true # deltas: bed_x is the diameter
|
|
396
|
+
# max_overhang = 50
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
Materials work the same way in `materials/` (`label`, `notes`, optional `clearance`).
|
|
400
|
+
|
|
401
|
+
## The checks
|
|
402
|
+
|
|
403
|
+
- **overlap** — intersection volume between every pair of `assembly(d)` parts; > 0.01 mm³ fails.
|
|
404
|
+
- **overhang** — downward faces in print orientation, angle from vertical (wall 0°, ceiling
|
|
405
|
+
90°); > 45° is reported, the bed face is ignored, flat ceilings are marked `bridge`.
|
|
406
|
+
`Overhang(part, fail=True)` for parts that must print without supports.
|
|
407
|
+
- **wall** — thinnest material in a cross-section, optionally only around one cut: across the
|
|
408
|
+
wall along the surface normal, and between separate outlines (hole to edge). Tips of ordinary
|
|
409
|
+
corners don't count as thin; knife edges sharper than about 25° do.
|
|
410
|
+
- **fit** — only with a printer profile: the part fits the build volume in print orientation.
|
|
411
|
+
- **probe** — material must be present (or absent) in a small box.
|
|
412
|
+
- **valid** — every printable part is a valid, non-empty solid.
|
|
413
|
+
|
|
414
|
+
## Sandbox
|
|
415
|
+
|
|
416
|
+
| Platform | Isolation |
|
|
417
|
+
| --- | --- |
|
|
418
|
+
| macOS | `sandbox-exec`: no network, no child processes, writes only to the part's `out/` and a scratch folder, home folder unreadable except the workspace |
|
|
419
|
+
| Linux with [bubblewrap](https://github.com/containers/bubblewrap) | no network, read-only system, same writable folders, home hidden |
|
|
420
|
+
| Linux without bubblewrap, Windows | separate process + audit hook only — **install bubblewrap, or use Docker** |
|
|
421
|
+
| Docker | the container (`--network none`, only the mounted folder) |
|
|
422
|
+
|
|
423
|
+
Every build also gets a timeout (default 120 s, `--timeout`) and a CPU limit. The audit hook
|
|
424
|
+
(blocks sockets, subprocesses, native libraries, writes elsewhere) is defense in depth, not a
|
|
425
|
+
boundary on its own.
|
|
426
|
+
|
|
427
|
+
## Updating
|
|
428
|
+
|
|
429
|
+
`b123d-print --version` (or the `version` field of the MCP `list_parts` tool) shows what you run.
|
|
430
|
+
Releases and what changed: [GitHub releases](https://github.com/KD5RYN/b123d-print/releases).
|
|
431
|
+
|
|
432
|
+
| Installed with | Update |
|
|
433
|
+
| --- | --- |
|
|
434
|
+
| `uvx --from git+https://github.com/KD5RYN/b123d-print ...` (MCP clients) | uvx caches the build: run `uvx --refresh --from git+https://github.com/KD5RYN/b123d-print b123d-print-mcp --help` once, then restart the client |
|
|
435
|
+
| a pinned version `...b123d-print@v0.1.0` | change the tag in your client config, restart the client |
|
|
436
|
+
| `uv tool install git+https://github.com/KD5RYN/b123d-print` (CLI) | `uv tool install --force git+https://github.com/KD5RYN/b123d-print` |
|
|
437
|
+
| Docker | `git pull && docker build -t b123d-print-mcp .` in your clone, restart the client |
|
|
438
|
+
| Claude Code plugin | `/plugin marketplace update b123d-print`, then restart Claude Code |
|
|
439
|
+
|
|
440
|
+
After updating:
|
|
441
|
+
|
|
442
|
+
- **Workspaces** keep your parts and settings. The workflow text in a workspace's `AGENTS.md`
|
|
443
|
+
is a copy; refresh it with `b123d-print init --update-agents` (MCP clients always get the
|
|
444
|
+
current text from the server).
|
|
445
|
+
- **Printer profiles** ship with the package and update with it; your own files in
|
|
446
|
+
`~/.config/b123d-print/` are never touched.
|
|
447
|
+
- **Part scripts**: while b123d-print is 0.x the script conventions may change; the release
|
|
448
|
+
notes say when, and `b123d-print check` tells you what breaks.
|
|
449
|
+
|
|
450
|
+
## Troubleshooting
|
|
451
|
+
|
|
452
|
+
| Symptom | Fix |
|
|
453
|
+
| --- | --- |
|
|
454
|
+
| First start is very slow, or the client gives up | it is downloading the dependencies; run `uvx --from git+https://github.com/KD5RYN/b123d-print b123d-print-mcp --help` once in a terminal, then restart the client |
|
|
455
|
+
| Client says `uvx` not found | use the full path from `which uvx` as the command |
|
|
456
|
+
| Model never looks at the renders | your client doesn't pass tool images to the model; open `out/*.png` yourself |
|
|
457
|
+
| `timed out after 120 s` | a slow or endless script; raise `--timeout` if the part is genuinely heavy |
|
|
458
|
+
| `blocked in part scripts: ...` | the script tried the network, a subprocess or files outside the workspace; part scripts only need build123d |
|
|
459
|
+
| Holes print small | calibrate `hole_comp` with the coupon |
|
|
460
|
+
| Linux: sandbox says "audit hook only" | install bubblewrap (`apt install bubblewrap`); on Ubuntu 24.04 unprivileged user namespaces must also be allowed — or use Docker |
|
|
461
|
+
|
|
462
|
+
## Platforms and status
|
|
463
|
+
|
|
464
|
+
**0.x — early.** The part-script convention may still change. CI tests macOS and Ubuntu, the
|
|
465
|
+
built package via `uvx`, and the Docker image on every push. Windows is untested: the MCP
|
|
466
|
+
server should run there without the OS sandbox; Docker is the safe route.
|
|
467
|
+
|
|
468
|
+
## Contributing
|
|
469
|
+
|
|
470
|
+
Issues and pull requests are welcome. To work on it:
|
|
471
|
+
|
|
472
|
+
```bash
|
|
473
|
+
git clone https://github.com/KD5RYN/b123d-print && cd b123d-print && uv sync
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
```bash
|
|
477
|
+
uv run pytest && uv run b123d-print check && uv run python tests/mcp_smoke.py
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
The printer table is generated: `python tools/sync_orca_printers.py` refreshes
|
|
481
|
+
`src/b123d_print/data/printers_orca.json` from OrcaSlicer (records the commit it used).
|
|
482
|
+
|
|
483
|
+
New checks and example parts should come from something that was actually printed.
|
|
484
|
+
|
|
485
|
+
## Credits
|
|
486
|
+
|
|
487
|
+
b123d-print is a thin layer over:
|
|
488
|
+
|
|
489
|
+
- [build123d](https://github.com/gumyr/build123d) — the Python CAD API every part is written in (Apache-2.0)
|
|
490
|
+
- [Open CASCADE Technology](https://dev.opencascade.org), via [OCP](https://github.com/CadQuery/OCP) — the geometry kernel (LGPL-2.1 with exception; bindings Apache-2.0)
|
|
491
|
+
- [lib3mf](https://github.com/3MFConsortium/lib3mf) — 3MF export (BSD)
|
|
492
|
+
- [OrcaSlicer](https://github.com/SoftFever/OrcaSlicer) — printer dimensions for the optional printer profiles (AGPL-3.0; facts only, no files copied)
|
|
493
|
+
- [matplotlib](https://matplotlib.org) and [NumPy](https://numpy.org) — renders, sections, check math
|
|
494
|
+
- [Model Context Protocol](https://modelcontextprotocol.io) and its [Python SDK](https://github.com/modelcontextprotocol/python-sdk) (MIT)
|
|
495
|
+
- [uv](https://github.com/astral-sh/uv) — packaging and `uvx`
|
|
496
|
+
|
|
497
|
+
Details and redistribution notes: [THIRD_PARTY.md](THIRD_PARTY.md).
|
|
498
|
+
|
|
499
|
+
## License
|
|
500
|
+
|
|
501
|
+
[MIT](LICENSE) © KD5RYN and contributors.
|