solidworks-bridge

Install?

adom-wiki pkg install adom/solidworks-bridge

Latest: v0.3.3, published

Download for your machine · v0.3.3?

v0.3.3 — no silent empties, retry-on-reject, add_component identity fix

Contents

README

markdown

SOLIDWORKS bridge (swx)

Say swx to the AI to reach this bridge. It drives the SOLIDWORKS desktop app on Windows over its COM API: streamlined file management, BOM generation from assemblies, and first-line design analysis — all from any Adom container, with SOLIDWORKS staying quietly in the background.

One native binary. No Python, no PowerShell, no interpreter to provision: ab spawns swx-bridge.exe directly (spawn.kind: "exe") and it is serving in about ten milliseconds.

What it does — 61 verbs

Area Verbs
Create & open swx_new_document (part/assembly/drawing from the stock template), swx_open, swx_import (STEP/IGES/Parasolid/STL), swx_save, swx_save_as, swx_close_doc, swx_find_files, swx_docs
Model swx_run_script — a typed modelling DSL: new_part, sketch_rect, sketch_circle, extrude, cut, set_material, set_prop, save_as, rebuild, zoom_fit. Everything in millimetres.
Macros swx_run_macroISldWorks::RunMacro2 on a .swp/.swb/.dll. Arbitrary code, so it needs the write opt-in every time. Scaffolding: not yet run live.
Export swx_export plus per-format aliases swx_export_step/iges/stl/3mf/glb/sat/parasolid/pdf/dxf/dwg, swx_pack_and_go
Read the design back swx_design_info, swx_inspect_bodies (geometry in mm), swx_get_parameters, swx_set_parameter, swx_mass_properties, swx_bom, swx_interference, swx_rebuild_check, swx_document_info
Metadata swx_props_get, swx_props_set (custom properties, file- or configuration-scope)
App & documents swx_get_app_state, swx_state, swx_status, swx_readiness, swx_progress, swx_start, swx_stop, swx_kill, swx_activate_document, swx_close_all_documents, swx_reset_workspace, swx_show_part/_assembly/_drawing
Windows & etiquette swx_window_info, swx_dismiss_blocking_dialogs, swx_close_window, swx_check_recovery, swx_screenshot, swx_set_driving_badge, swx_action_ledger, swx_verb_times
Preferences & cloud swx_get_preferences, swx_set_preference, swx_cloud_status
Bridge swx_describe, swx_com_eval, swx_uninstall

Verb names and arg names deliberately mirror the Adom Fusion 360 bridge (outputPath, filePath, name, parameters, bodies, current, applied, stages, wouldPrompt) so an AI that already knows fusion_* can drive swx_* with nothing new to learn. docs/FUSION-PARITY-REPORT.md covers all 132 Fusion verbs with a verdict, and is where the divergences are argued.

Two things to know before you drive it

SOLIDWORKS Connected is launched through the Platform's own shortcut. On the 3DEXPERIENCE editions (including Design Professional for Makers), CoCreateInstance spawns a process that refuses with "SOLIDWORKS Design must be launched from the 3DEXPERIENCE Platform" and never attaches — verified live, and for two rounds this bridge concluded from that the edition could not be started at all. That was a conclusion about the wrong experiment. The Start-Menu shortcut the Platform installs does not run sldworks.exe; it runs

CATSTART.exe -run "SWXDesktopLauncher.exe"
             -object "--AppName=\"SWXCSWK_AP\" -tenant=<TENANT> -monoapp
                      -3DRegistryURL=https://<region>-makers-registry.3dexperience.3ds.com"
             -nowindow

so the refusal was ours, for bypassing the launcher chain. swx_start now invokes that shortcut — the sanctioned artefact, carrying the user's own tenant, with nothing reverse-engineered and no argument invented — then polls for the COM server. A cold start runs 1-3 minutes, so it answers started:true, stillLaunching:true while the application comes up rather than holding the request. Classic desktop installs still attach directly over COM. errorCode:"host_app_launch_blocked" now means only that no shortcut could be found (SWX_SOLIDWORKS_SHORTCUT points the bridge at one).

Exports are copies; save-as is a rename. swx_export* uses SaveAs3 in Silent|Copy mode, so the open document keeps its identity (v0.2 did not, and silently renamed it). swx_save_as is the deliberate rename; copy:true makes it a copy. And because SaveAs3 picks the format from the DESTINATION EXTENSION rather than the format argument, that is where the format rules are enforced — swx_export_step {"outputPath":"x.wrl"} is refused.

Writes are DENY-BY-DEFAULT. These verbs pass through one choke point (src/writes.rs), which refuses unless both: the document is one this bridge created in this SOLIDWORKS session, and the destination path does not already exist —

swx_save · swx_save_as · swx_export and its ten format aliases · swx_bom {format:"csv"} · swx_pack_and_go · swx_close_doc · swx_props_set · swx_set_parameter · swx_set_preference · swx_run_script · swx_rebuild_check (it calls ForceRebuild3) · swx_stop and swx_close_all_documents (which end the user's session, and are gated unconditionally) · swx_run_macro (always gated: a macro is a VBA project with the whole API in scope, and nothing about the call predicts what it will touch).

The gate opens BOTH ways. When the user has opted in, in full, the bridge does the thing — it does not refuse anyway. The server and the com host check the identical chain independently, so a partial chain is refused twice and a complete one is honoured by both.

Anything refused returns errorCode:"user_writes_disabled", "destination_exists" or "not_bridge_document". Exporting from any document to a path that does not exist always works — that is the normal way to get data out, and it needs no permission.

The only way past it is a deliberate opt-in that a caller cannot grant itself: the bridge process must be started with SWX_ALLOW_USER_WRITES=1 and the call must carry allowUserWrites:true, confirm:true and a reason. Every granted exception is recorded in swx_action_ledger. swx_status and swx_describe report userWrites: "disabled"|"enabled" so a caller knows the posture before it plans anything.

The same rule covers ending or disturbing the user's session: swx_stop, swx_kill, swx_close_all_documents, and closing ANY dialog — swx_dismiss_blocking_dialogs {close:true} and swx_close_window alike, including dialogs the bridge itself raised. swx_close_window additionally refuses an application frame outright (closing one quits SOLIDWORKS, which is swx_stop's job) and refuses a dialog that asks about the user's own work (Save changes?, Document Recovery, licence) at any posture. It also covers swx_open {readOnly:false}, which takes a write lock on the user's file and converts-and-dirties an older-version document in memory.

For everything that reaches SOLIDWORKS, the com host enforces the same two rules independently, on its dispatch loop rather than per command: it keeps its own record of the documents it created (stamped with the SOLIDWORKS session, so a crash or a restart invalidates it), reads the opt-in from its own environment, and refuses any command not on its no-side-effects list. A command added tomorrow is therefore deny-by-default.

Where there is only one veto, and why: swx_kill, swx_close_window, swx_dismiss_blocking_dialogs and swx_screenshot go out through ab rather than the com host, so the host's veto is not in their path — the server-side choke point is the only check they have. That is worth knowing when reading the rest of this section. swx_screenshot captures BY HANDLE (the one COM reports, or an hwnd swx_window_info attributes to SOLIDWORKS); it will not take a picture of an arbitrary window on the desktop.

This posture is a response to five consecutive rounds of adversarial review, in each of which the bridge turned out to be able to write to the user's data through a route whose guard had been forgotten. Gating routes failed five times; denying by default at one choke point removes the class.

Architecture

ab (Adom Bridge) ── HTTP /command ──> swx-bridge.exe            (server mode)
                                         │  JSON-lines over stdio
                                         └─> swx-bridge.exe --com-host
                                             (child process holding the live
                                              SldWorks.Application COM object)
  • One exe, two modes. The server spawns the com host from its own current_exe(), so there is exactly one file to ship and one image name for ab to stop (killImageName: "swx-bridge.exe" covers both processes).
  • The COM object lives in a CHILD PROCESS, not a thread. A wedged COM call — SOLIDWORKS parked on a modal dialog, a rebuild that never returns — cannot be killed as a thread. It can be killed as a process. The server owns that lifecycle: lazy spawn, one request in flight, per-request timeout, kill and respawn after a crash or hang, and the child's stderr tail surfaced in the failing verb's detail. A child that dies between requests is replaced transparently, so the next verb works.
  • The child is persistent: it attaches to (or launches) SOLIDWORKS once and keeps the COM object, so verbs don't pay a per-call attach. It is initialized as an STA and holds the apartment for its whole life. On Windows it is spawned with CREATE_NO_WINDOW — no console ever blips on the user's desktop — and it exits on its own when its parent goes away (stdin EOF), so nothing is left holding a COM object.
  • Late-bound IDispatch (GetIDsOfNames + Invoke), like every SOLIDWORKS macro: it works against whichever version is installed, with no interop assemblies to match.
  • Mock mode (SWX_MOCK=1, automatic on non-Windows) swaps the COM backend for an in-memory fake behind the same Backend trait — same protocol, same response shapes — so the whole verb surface is testable with no SOLIDWORKS and no Windows.

Host app status

SOLIDWORKS is a detect-only host app (ab tier-2): Dassault publishes no silent installer — desktop trial serials come from a reseller, and the Makers edition comes from the 3DEXPERIENCE Platform store — so the bridge reports absence with errorCode:"host_app_not_installed" and a next-steps _hint instead of ever attempting an install. The verbs that need no COM (swx_status, swx_readiness, swx_describe, swx_progress, swx_find_files, swx_action_ledger, swx_verb_times, swx_uninstall) work regardless, so "what CAD files do I have?" is answerable today.

Export formats, verified rather than assumed

Every format below was exported from a real solid on a live SOLIDWORKS Design Professional for Makers 2026 and the bytes on disk were checked — with the caveat that those probes used SaveAs3 with Silent ALONE, which is how the rename bug was found. The shipped export path uses Silent|Copy and has never run; whether Copy is valid for PDF/PNG/JPG/TIF is unknown. Read the table as "SOLIDWORKS can write this format", not "the bridge's export path is proven":

Works from a part Refused for a part (code 256) Blocked by this bridge
STEP, STP, IGES, STL, X_T, X_B, SAT, 3MF, GLB, PLY, AMF, 3DXML, PNG, JPG, TIF, XAML, PDF OBJ, DXF, DWG, U3D (DXF/DWG are drawing formats) VRML (.wrl)

VRML is refused outright with errorCode:"format_blocked": it raises a modal option sheet that no unattended caller can answer, and on the live install it hung the COM call until the watchdog killed the host.

Development

cargo build                                      # native (mock mode: no SOLIDWORKS needed)
cargo test                                       # unit + HTTP e2e + protocol e2e
cargo build --release --target x86_64-pc-windows-gnu   # the shipped swx-bridge.exe

# run it by hand and poke it
SWX_MOCK=1 cargo run -- --port 24695
curl -s localhost:24695/status | jq
curl -s localhost:24695/command -d '{"command":"swx_describe","args":{}}' | jq

The suite is built so it cannot lie:

  • No test asserts by reading source. Every check drives the real compiled binary (CARGO_BIN_EXE_swx-bridge) over HTTP or over the stdio protocol.
  • A verb-coverage gate compares the verbs actually CALLED during the suite against bridge.json, in both directions, and against swx_describe. A new verb shipped without a test turns the suite red.
  • Response invariants on every call: 200, parses as JSON, boolean success; malformed bodies get a clean 400, never a 500.
  • Effects, not existence: exports are read back off disk, the BOM CSV is parsed and its columns checked, find_files runs against real fixture files.
  • Protocol e2e: the real server driving the real com-host child, including crash recovery (kill the child, the next verb still works), junk on the child's stdout, orphan cleanup, and a slow verb that must not block swx_progress.

Everything the bridge writes goes under one root (%LOCALAPPDATA%\Adom Bridge\bridges-cache\solidworks\, or SWX_SCRATCH_DIR for tests), pruned at 48h / 300 files, and removed in full by swx_uninstall.

swx_com_eval {"expr":"$sw.RevisionNumber()","reason":"..."} is the maintainer escape hatch: a late-bound call chain rooted at $sw or $doc, for proving out a new capability against a real install before it becomes a verb.

Live validation

Mock-green is not green: v0.2 passed 49 mock tests while shipping four COM bugs, all of which the first live session found (see the parity report). Three tools close that gap:

python3 tools/swx-live.py <verb> '<json>' [timeoutSec]   # one verb on the desktop
python3 tools/swx-batch.py calls.json                    # many verbs in ONE round trip
python3 tools/live-smoke.py                              # the full live suite

live-smoke.py creates its own scratch part, builds a real 50×30×20 mm solid, reads the geometry back, drives a dimension, exports eight formats, checks the bytes on disk, and then asserts SOLIDWORKS is left with exactly the documents it started with. It never opens, saves or closes a document it did not create, and it never launches or stops SOLIDWORKS.

Roadmap

  • v0.1: full verb surface in Python + a PowerShell COM sidecar, mock-tested.
  • v0.2: single Rust binary — 23 verbs, COM in a killable child process, crash recovery, a suite that drives the real binary.
  • v0.3.1 (this): the launch answer — SOLIDWORKS Connected starts through the Platform shortcut, so host_app_launch_blocked now means only "no shortcut found"; swx_run_macro scaffolding; and the write opt-in made openable on every path it guards (three live-proven cases where the human authorized an action in full and the bridge refused anyway — an escape hatch nobody can open is not a safety property).
  • v0.3: 60 verbs at Fusion-360-bridge parity — document creation, a modelling DSL, geometry read-back, parameters, per-format exports, window and dialog etiquette, an action ledger and measured verb timings. First live shakedown against a real SOLIDWORKS; four v0.2 COM bugs diagnosed with live evidence and fixed on reasoning (the fixes themselves are unverified — see the parity report). Writes made deny-by-default after five rounds of review.
  • v0.4 candidates: drawing (.slddrw) BOM-table extraction and DXF/DWG/PDF from drawings, per-component mass properties for assemblies, configuration management, a live screen feed, and — the big one — 3DEXPERIENCE 3DSpace access, which needs its own OAuth story.