Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- **The U-joint demo** (#175, #207). SolidWorks' U-Joint sample, written up
as a prompt and built by Claude Code (Opus 5.5, medium effort) in 294
tool calls, is the top demo in the README and on the Demos page, beside
the original. The same prompt with and without the agent skill made the
same parts; the skill page records the comparison.
- **The monitor stand, printed.** The monitor-stand demo now shows the
stand on the printer.

- **An agent skill for using the server** (#175). `solidworks-mcp skill
install` puts the `solidworks-mcp` skill in Claude Code's skills folder
(`--project` or `--dir` for others); it covers the build order, units
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@ Python MCP server for SolidWorks automation with 154 tools, plus an optional age

## See it work

### A whole mechanism from a description

We took SolidWorks' own U-Joint sample, read every part, sketch, feature and mate, and wrote it up as a plain-English prompt: eight parts, a crank sub-assembly, and a main assembly that has to move like a real joint. Then Claude Code (Opus 5.5, medium effort) built it from that prompt alone.

![The original U-Joint sample beside the agent's build: the same bracket, yokes, spider, pins, crank and knob, in the same pose](docs/assets/demos/ujoint/ujoint_original_vs_agent.jpg)

![The agent's 294 tool calls replayed in SolidWorks: eight parts sketched and cut, then the crank sub-assembly and the U-joint mated together](docs/assets/demos/ujoint/test_ujoint_from_prompt_to_assembly-motion.gif)

Six of the eight parts match the sample's volume within 0.2 %, and all eight within 1 %. The mates leave the mechanism free to turn. The recording replays the session's 294 calls (sped up 80 times). The [walkthrough](https://andrewbartels1.github.io/SolidworksMCP-python/demos/#ujoint) has the prompt, the part-by-part comparison, and what the agent couldn't do. The same prompt run with and without the [agent skill](https://andrewbartels1.github.io/SolidworksMCP-python/agents/agent-skill/) made the same parts, which is why we want skills that improve results (#207).

### A drawing package from one prompt

> Make a 100 x 50 x 10 mm AISI 1020 mounting plate with four M5 clearance holes, 10 mm in from each edge, and draw it fully dimensioned. Stack two of them 10 mm apart, check the result, and draw the assembly with a BOM.

![A fully dimensioned plate, its drawing with GD&T, two plates mated 10 mm apart and the assembly drawing with a BOM, built in SolidWorks through the MCP tools](docs/assets/demos/readme/test_plate_stack_from_prompt_to_drawing-motion.gif)
Expand Down
51 changes: 50 additions & 1 deletion docs/agents/agent-skill.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,61 @@ replacing older copies of them and leaving any other file there alone. It
reads nothing but the packaged skill (no client config, no other skill) and
needs no network or login. Re-run it after upgrading the server.

## Does it help? Measured on the U-joint

The skill was tested on a hard prompt: rebuild SolidWorks' own U-Joint
sample, eight parts, a crank sub-assembly and a main assembly that must move
as a mechanism, from a plain-English description (see the
[U-joint demo](../demos.md#ujoint)). Claude Code with **Opus 5.5 at medium
effort** ran it in fresh sessions on the same SolidWorks: once with the skill
installed and the server instructions, once without either. Both had the same
tool descriptions.

| | With skill | Without skill |
| --- | --- | --- |
| Time | 23.5 min | 21.9 min |
| SolidWorks tool calls | 294 | 268 |
| SolidWorks errors | 3 | 7 |
| `verify_model` checks | 17 | 8 |
| Output tokens | 451k | 385k |
| Main assembly | 7 parts, rotations left free | 7 parts, 20 mates, motion tested with a temporary 30° mate |

Part volumes (mm³) against the original sample:

| Part | Sample | With skill | Without skill |
| --- | --- | --- | --- |
| bracket | 56,363.5 | 56,922.8 | 56,922.8 |
| Yoke_male | 30,825.7 | 30,777.8 | 30,777.9 |
| Yoke_female | 27,252.8 | 27,210.2 | 27,210.2 |
| spider | 4,775.0 | 4,775.0 | 4,775.0 |
| pin | 2,642.9 | 2,642.9 | 2,642.9 |
| crank-shaft | 5,948.8 | 5,935.5 | 5,935.6 |
| crank-arm | 8,206.4 | 8,206.4 | 8,206.4 |
| crank-knob | 7,528.1 | 7,528.1 | 7,528.1 |

The bracket's extra 1 % is the corner where its lip meets the foot: the
sample's thin feature trims it, and the prompt never described it. The
crank shaft's 0.2 % is its collar fillets, which are larger than the step they
sit on (both sessions said so).

**The takeaway:** for Opus 5.5 at medium effort, this skill changed *how* the
agent worked (fewer errors, twice the checking, about 17 % more tokens), not
*what* it built: both sessions made the same parts. The tool descriptions
already carry what the skill says. A skill earns its tokens only when it adds
what the model can't get from the tools, such as mates that leave a mechanism
free to move, reference-geometry recipes and design-intent checks. We need
new and better skills, and [#207](https://github.com/andrewbartels1/SolidworksMCP-python/issues/207) tracks writing and measuring them.

One run per arm is a single data point. An earlier pair of runs, before the
prompt was corrected, came out the same way. Record the model and effort
level with every measurement.

## Keeping it true

`tests/integration/test_skill_content.py` fails when the skill or the
instructions name a tool that isn't registered, or send an agent to a tool
that can't run yet (those may be named only in the limits reference, which
lists them). When a fault in `openspec/queue.md` item 10 is fixed, remove
lists them). When a fault in `openspec/queue.md` (the small-faults list) is fixed, remove
it from `references/errors-and-limits.md` in the same change.

For changing the server's COM code, the contributor reference is
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
129 changes: 127 additions & 2 deletions docs/demos.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,138 @@ captioned beneath the SolidWorks window.
Each entry has:

- **what it shows**, and what the run checked;
- **the prompt**: the real one for the prompt-to-drawing and monitor-stand
demos. The other demos are live tests that call the tools directly, so
- **the prompt**: the real one for the U-joint, prompt-to-drawing and
monitor-stand demos. The other demos are live tests that call the tools directly, so
their prompt is an example of what you would type to get the same calls;
- **the tool calls**, in order;
- **the source**: the test that made the GIF. Run any of them yourself (see
[Run a demo yourself](#run-a-demo-yourself)).

## A whole mechanism from a description: the U-joint {#ujoint}

![The original U-Joint sample beside the agent's build: the same bracket, yokes, spider, pins, crank and knob, in the same pose](assets/demos/ujoint/ujoint_original_vs_agent.jpg)

SolidWorks ships a U-Joint sample (`samples/learn/U-Joint`): a bent bracket,
two yokes, a spider, pins and a hand crank, eight parts in a crank
sub-assembly and a main assembly. We read every part, sketch, feature,
dimension and mate from it, wrote it up as a plain-English prompt, and gave
that prompt to Claude Code (**Opus 5.5, medium effort**) with the server and
the [agent skill](agents/agent-skill.md) installed. It built all ten files in
23.5 minutes and 294 SolidWorks calls, with 3 errors it recovered from.

![The agent's 294 tool calls replayed in SolidWorks: eight parts sketched and cut, then the crank sub-assembly and the U-joint mated together](assets/demos/ujoint/test_ujoint_from_prompt_to_assembly-motion.gif)

The recording opens on the original sample, then replays the session's 294
calls through an MCP client, each captioned with its result (sped up 80
times). Every call ended as it did in the session.

??? example "The prompt"

> I want to build a small hand-cranked universal joint in SolidWorks: eight parts, a crank sub-assembly, and the main assembly. It's a mechanism: turning the knob turns the crank, which drives the joint through an angle, so the assemblies must still move the way described in sections 9 and 10. Please reason through each part before you start drawing, check every part once it's built, and tell me if something can't be done with the tools rather than guessing. All sizes are in millimetres (the original was drawn in inches, so the numbers are odd). SolidWorks' Y axis is up. Save every part and both assemblies in this folder, with the names given below.
>
> **1. bracket.SLDPRT: a bent plate, 6.35 mm thick and 38.1 mm wide.**
> Seen from the side (sketch on the Right plane, Y up, Z towards the front), the inside outline of the bend is an open chain:
> - a back wall going straight up 82.55 mm from the origin;
> - from its top, a top arm going forward 57.15 mm;
> - from the origin, a bottom foot going forward 44.45 mm;
> - from the front of the foot, a lip rising at 40° for 42.77 mm (it ends 27.49 mm up and 77.22 mm forward).
> The 6.35 mm thickness is on the outside of that outline: above the top arm, behind the back wall and under the foot. The 38.1 mm width is centred on the Right plane. Drill a 12.7 mm hole straight down through the top arm and on through the foot below it (one cut, both plates), centred across the width and 38.1 mm forward of the back wall's inside face.
>
> **2. Yoke_male.SLDPRT: a fork with a stub shaft.**
> - Start with a 38.1 mm diameter cylinder, 47.625 mm tall, standing on the Top plane.
> - Its bottom becomes a fork with two ears. Each ear is 19.05 mm wide and 8.89 mm thick, and the gap between them is 20.32 mm, centred. Each ear has a rounded end: a full radius of 9.525 mm, centred 9.525 mm above the bottom. Where an ear meets the solid part of the cylinder, round the shoulder with a 9.525 mm radius, so the solid part starts 29.21 mm above the bottom.
> - Drill a 9.525 mm cross hole through both ears at the centre of their rounded ends, square to the ears.
> - On top, add a 12.7 mm diameter stub, 19.05 mm tall, on the cylinder's axis. Chamfer its top edge 1.27 mm at 60°.
> - Cut a flat on the stub, 12.7 mm long down from its top. The flat is 4.7625 mm from the axis, so it is 1.5875 mm deep.
>
> **3. Yoke_female.SLDPRT:** the same 38.1 x 47.625 mm cylinder with the same fork and the same cross hole as the male yoke, but no stub. Instead, a 9.525 mm hole goes all the way through along its axis.
>
> **4. spider.SLDPRT:** a 19.05 mm cube centred on the origin. It has two 9.525 mm holes, both through its centre: one front to back, and one left to right.
>
> **5. pin.SLDPRT:** a 9.398 mm diameter rod, 38.1 mm long.
>
> **6. crank-shaft.SLDPRT: a 12.573 mm diameter shaft, 40 mm long, standing on the Top plane.**
> - Around its bottom 15.875 mm, a collar 18.923 mm in diameter.
> - A 4.763 mm fillet where the collar meets the shaft, and a 4.763 mm fillet on the collar's top outer edge.
> - In the bottom, a D-shaped socket 12.7 mm deep. It is a 12.954 mm circle with a flat 4.889 mm from the axis, to take the male yoke's stub.
> - A 2.381 mm cross hole through the collar wall, square to the socket's flat and 6.35 mm up from the bottom.
> - At the top, a matching flat 6.35 mm long, 4.889 mm from the axis.
> - A 0.794 mm x 45° chamfer on the top end.
>
> **7. crank-arm.SLDPRT: a flat bar, 75 x 19.05 x 6.35 mm.**
> - Near one end, a 12.7 mm D-hole centred 9.525 mm from the end and on the bar's centreline. Its flat is 4.889 mm from the hole's centre, towards that end. It fits the shaft's top flat.
> - Near the other end, a 4.763 mm hole 9.525 mm from that end, also on the centreline.
>
> **8. crank-knob.SLDPRT: a mushroom-shaped knob, revolved 360° about the vertical axis.** Going up from the bottom, its profile has:
> - a 4.572 mm diameter shank, 6.35 mm long;
> - a step out to a 9.525 mm diameter;
> - a concave quarter-round of radius 6.35 mm that flares out to 22.225 mm diameter, 12.7 mm up;
> - a convex half-round of radius 4.7625 mm that reaches 31.75 mm diameter at its widest;
> - a flat top 22.225 mm in diameter, 22.225 mm above the bottom.
>
> **9. crank sub.SLDASM:**
> - The crank shaft is fixed.
> - The crank arm's D-hole goes on the shaft's top flat: the hole is concentric with the shaft, the flats are parallel, and the arm sits on the shoulder where the flat starts. The flats lock the arm to the shaft, so they turn together.
> - The knob's shank goes into the arm's small hole, with the knob's step resting on the arm's top face. The knob stays free to spin in its hole, like a handle.
>
> **10. UJoint.SLDASM:**
> - The bracket is fixed.
> - The male yoke hangs under the bracket's top arm. Its stub goes up through the bracket's hole (concentric), and the top of its cylinder is flat against the underside of the arm. It must stay free to turn in that hole.
> - The spider sits centred between the male yoke's ears, with one of its holes lined up with the ears' cross hole. It pivots on that axis.
> - The female yoke's ears go around the spider's other hole, centred on the spider. Its top face is parallel to the bracket's sloped lip, so its axis points down and forward. It pivots on the spider and turns about its own axis.
> - Put one pin through the male yoke's ears and the spider, and one pin through the female yoke's ears and the spider. Each pin's ends are flush with its yoke's round outside, and each pin turns with its yoke.
> - Insert the crank sub-assembly. Its shaft's D-socket goes over the male yoke's stub: concentric, with the flats parallel, and the bottom of the shaft 1 mm above the top of the bracket. The flats lock the crank to the male yoke.
> - The result should be a mechanism with one free motion: turning the knob around the crank shaft's axis turns the male yoke, the spider rocks on its pins, and the female yoke turns about its tilted axis. Choose mates that leave exactly those rotations free and lock everything else.
>
> When it's all built, check each part's size and the assembly's component and mate counts, say which rotations your mates leave free, and tell me what you couldn't do.

**How close it got.** Part volumes in mm³, read back by `verify_model`:

| Part | Sample | Agent | Difference |
| --- | --- | --- | --- |
| bracket | 56,363.5 | 56,922.8 | +1.0 % (sharp bends; the sample's are rounded, and the prompt gave no bend radius) |
| Yoke_male | 30,825.7 | 30,777.8 | −0.16 % |
| Yoke_female | 27,252.8 | 27,210.2 | −0.16 % |
| spider | 4,775.0 | 4,775.0 | 0 |
| pin | 2,642.9 | 2,642.9 | 0 |
| crank-shaft | 5,948.8 | 5,935.5 | −0.22 % |
| crank-arm | 8,206.4 | 8,206.4 | 0 |
| crank-knob | 7,528.1 | 7,528.1 | 0 |

The main assembly has the bracket fixed and seven components, mated so that
turning the knob turns the crank and male yoke, rocks the spider and turns the
female yoke about its tilted axis.

**What it couldn't do, and said so:**

- The two full-length pins cross inside the spider (553 mm³ of overlap). The
sample has the same clash; a real joint uses one long and two short pins.
- The crank shaft's 4.763 mm collar fillets are larger than the 3.175 mm step
they sit on, so SolidWorks blends them into one curve.
- `add_mate` can't pick faces, and no tool can fix a part or make a
sub-assembly flexible, so the knob spins only inside the crank
sub-assembly. There's no angled plane or 60° chamfer either: it used an
angle mate and drew the chamfer into the profile. These gaps are #209.

**With and without the skill.** The same prompt, run without the skill or the
server instructions, made the same parts to within 0.1 mm³: with the skill
the agent hit fewer errors (3 against 7) and checked its work twice as often.
For Opus 5.5 at medium effort, the skill changed how the agent worked, not
what it built. The full comparison is on the
[agent skill page](agents/agent-skill.md#does-it-help-measured-on-the-u-joint),
and [#207](https://github.com/andrewbartels1/SolidworksMCP-python/issues/207)
tracks writing skills that improve results.

**Source:** [`tests/live/test_live_sw_ujoint_demo.py`](https://github.com/andrewbartels1/SolidworksMCP-python/blob/main/tests/live/test_live_sw_ujoint_demo.py),
replaying [`with_skill_calls.json`](https://github.com/andrewbartels1/SolidworksMCP-python/blob/main/tests/live/data/ujoint/with_skill_calls.json).
Record it with:

```powershell
powershell -ExecutionPolicy Bypass -File tests\scripts\live_demo.ps1 `
-Test tests/live/test_live_sw_ujoint_demo.py `
-CaptureDir docs/assets/demos/ujoint -Record -PromptSeconds 12
```

## From a prompt to a printable monitor stand {#monitor-stand}

![The user's prompt, then an arched monitor stand built in SolidWorks through the MCP tools: a block, two cuts leaving four legs, arches at the front and sides, a pocket for the monitor's base, checked, saved and exported as an STL, ending in an isometric view](assets/demos/monitor-stand/test_monitor_stand_from_prompt_to_part-motion.gif)
Expand Down
19 changes: 14 additions & 5 deletions openspec/changes/agent-skill-and-instructions/tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,17 @@
## 5. Ship

- [x] 5.1 Full mock suite, ruff, 100 % coverage, `mkdocs build --strict`
- [ ] 5.2 Ask the user, then run the measurement on real SolidWorks: the
chosen demo prompt in a fresh agent session without the skill, then
with it installed; record tool calls, errors and whether
`verify_model` passed, in the PR and in `docs/agents/` (paced runs,
`SW_TEST_PACE_SECONDS=4`)
- [x] 5.2 Ask the user, then run the measurement on real SolidWorks: the
U-joint prompt (SolidWorks' U-Joint sample, read part by part and
written as a plain-English prompt) in a fresh agent session without the
skill, then with it installed, each from a clean folder with the same
breaker timeout; record tool calls, errors, part volumes against the
sample and the mates, in `docs/agents/agent-skill.md` (decided
2026-11-06: the monitor stand was too easy to show a difference)
- [x] 5.3 `tests/live/test_live_sw_ujoint_demo.py`: open on the original
sample, then the prompt, then replay the with-skill session's calls
(`tests/live/data/ujoint/`) as captioned frames, each ending as it did
in the session; record it with `live_demo.ps1 -Record`
- [x] 5.4 README and Demos page: the U-joint as the top demo, above the
monitor stand, showing the original beside the agent's result and the
with/without comparison
Loading
Loading