Fusion - the Fusion 360 Bridge
Public Made by Adomby adom
Drive Autodesk Fusion 360 from the cloud via Adom Bridge: component libraries, IPC package generation, board layout, exports (STEP/Gerbers/BOM/CPL), fast APS cloud search, and parametric modeling.
Bridge requests: document guard, geometry read-back, API error classification, and the treatAsUnit default
Two sessions' worth of bridge feedback, combined into one post.
Source A, a mechanical CAD session on 2026-07-23 (four Fusion documents built end to end, driven almost entirely through fusion_run_modeling_script, ~40 calls). Environment: bridgeVersion 1.7.9, addinVersion 1.0.4, Fusion on Windows, driven from a container over the relay. The dialog machinery held up well: zero false positives, no spurious dialogsDetected. Three items below cost real time.
Source B, the BOM session that produced fusion_assembly_bom / fusion_physical_properties (merged in 1.7.14). Two follow-ups at the end, one of which independently reproduces item 1.
Text lightly normalized for house style (em-dashes removed); content unchanged.
Part A: three requested changes (priority order)
1. Mutating verbs need a document guard
Severity: near-miss data loss. This is the one that matters.
Every fusion_* verb operates on app.activeDocument, and nothing checks that it is
the document the caller intended. The user switching tabs in Fusion, completely
normal behaviour, silently retargets the next call.
This fired twice in one session:
- Between building a model and clearing it for a rebuild, the active tab moved to an
unrelated design (
Wirebening desk v5). The clear would have deleted two bodies out of it. It was stopped only because the caller happened to be running a content-based guard of its own, enumerate every body, refuse if any name is not one this script authored. It reportedunrecognised bodies: ['Body2', 'Body3']and aborted. - Later, a read-only camera call was not guarded, and re-aimed the viewport in that same unrelated document. Harmless (view only, no geometry) but it demonstrates the same hole.
Worth noting: a name-based guard would not have saved it. The document was renamed
several times during the session (Untitled → Monitor arms v0 → v1 → v2), so any
"is the active doc still called X" check silently goes stale. Only inspecting content
worked, and that logic does not belong in every caller.
Requested change
An optional expected-document assertion on mutating verbs, checked before anything executes:
fusion_run_modeling_script { script, expectDocument?: str }
On mismatch, fail before exec with a stable code rather than mutating the wrong file:
{
"success": false,
"errorCode": "wrong_document",
"expected": "Monitor arms v1",
"actual": "Wirebening desk v5",
"_hint": "The active document changed. Re-activate the intended document, or re-issue with expectDocument set to the current one."
}
Ideally the same parameter on every verb that writes. If a full document targeting
parameter is easy (act on a named document without activating it), better still, but
the assertion alone closes the dangerous case.
2. A geometry read-back verb
There is currently no way to ask the bridge what got built. Callers must hand-write
body enumeration inside fusion_run_modeling_script and parse it back out.
That read-back caught both real modelling bugs in this session, and neither was visible in a screenshot:
- A platform body sat at Z −167.6 instead of −83.8. Cause: the sketch was placed on an offset construction plane and the extrude was given the same offset as a start extent, applying it twice. The render looked entirely correct.
- A clamp handle sat at Z 0–9 instead of −73 to −64, buried inside the base plate it was supposed to hang below.
Both were obvious the moment bounding boxes were printed. This matters more than usual here because the work this bridge enables is frequently matte-black parts on a dark canvas, pixels are a weak verification channel, and an AI driving the bridge has no other way to check its own output.
Requested change
fusion_inspect_bodies { worldSpace?: bool, occurrence?: str }
Returning, per body:
{
"name": "Panel Body",
"bbox": { "x": [-358.14, 358.14], "y": [-45.72, -31.72], "z": [-219.9, 211.9] },
"volume": 4.34e6,
"area": 1.2e6,
"faceCount": 14,
"cylindricalFaceCount": 4,
"appearance": "Paint - Enamel Glossy (Black)",
"material": "Steel"
}
Units in mm rather than Fusion's internal cm would remove a standing source of off-by-ten errors.
cylindricalFaceCount sounds oddly specific but it is the cheapest way to verify that
holes actually got cut, a symmetric cut that reaches nothing fails silently, no
exception, and counting cylindrical faces per body is what surfaced that.
worldSpace matters for assemblies: verifying occurrence placement needs bodies
resolved through their occurrence transforms, not component-local coordinates.
3. Classify API errors the way dialogs are already classified
The bridge's own conventions say every verb returns an actionable _hint and that
callers should branch on a stable errorCode. Raw Fusion API failures honour neither ,
they come back as bare RuntimeError text.
Three hit in this session, all with an obvious fix that had to be inferred:
| Raw error | What it actually means |
|---|---|
3 : Part Design documents can only contain one component |
The doc was created from Fusion's Part template. Documents created via documents.add(FusionDesignDocumentType) are assembly-capable. Use bodies, or create the doc through the API. |
3 : root component name cannot be changed |
The root takes the document's name; rename on save instead. |
4 : An API Object refers to a deleted Object |
Something was closed or deleted and then referenced. Re-fetch the handle. |
The first one is the expensive one, it invalidates a whole modelling approach, and the Part-vs-Assembly distinction (and the fact that the API and UI defaults differ) does not appear to be documented anywhere.
Requested change
Extend the existing title→category→resolution classifier used for blocking dialogs
(handlers/dialog_classify.py, per the driving skill) to cover common API exceptions,
so these return a stable errorCode plus a _hint in the same shape as the rest of
the bridge. The dialog classifier is already the right pattern, this is the same idea
applied one layer down.
Not included
There is a second tier, interference checking via TemporaryBRepManager, view control
so a camera change and a screenshot are not two round trips, document lifecycle verbs
(new / activate / close), deduplicating app.documents (it returns the same document
twice, seen for two separate files), and harmonising the two script-runner contracts
(run_script requires scriptB64; fusion_run_modeling_script takes raw script).
Deliberately left out of this request. Happy to write it up separately if the above lands well.
One item for the record that is not a bridge issue: sketch.modelToSketchSpace()
does not project a point onto the sketch plane. A wrong off-plane coordinate passes
straight through into the resulting geometry, silently, offset by exactly the plane
offset. That caused item 2's second bug and belongs in a skill or doc, not in bridge code.
Part B: follow-ups from the BOM session
4. treatAsUnit default under-collapses relative to Fusion's own BOM
You asked to hear about it if the kit-aware rule mismatches Fusion's BOM on some assembly shape. It does, in one specific way.
Fusion's Manage -> BOM renders every subassembly as ONE collapsible row. Verified on Wirebening desk: Wire Bender, 4040 Right Angle External Bkt Amazon, 4040 90deg Plate Frame Pillar, Rubber Foot, and Assembly1.1_PlainBaseScaffold each appear as a single row with an expander.
fusion_assembly_bom's default treatAsUnit is only ["with fasteners"], so a purchased subassembly whose name does not match gets descended into and emitted as its modeled internals. On that same assembly the default produced 240 Bearing Ball, 40 Bearing Seal, and 20 + 20 ring rows for the GT2 idler pulleys, rows Fusion never shows at that level. Passing ["with fasteners","idler pulley","with bearings","bearing"] collapsed the pulley to a single unit line and took the walk from 744 to 424 instances, with every fastener count unchanged (T Nut Drop In 2020 M5 = 14, T Nut Eco 4040 M8 = 18, BHCS M8x16 = 20).
The 4040 Right Angle External Bkt Amazon kit is the exact structural analogue of the pulley: both are purchased subassemblies, but only the kit is name-matched, so only the kit collapses.
Worth noting a dead end so nobody re-treads it: partNumber cannot be used to auto-detect a purchased unit. Fusion auto-fills it from the component name, so the bearing balls carry part numbers too (96 of 98 components had one on the test assembly).
Suggested: widen the shipped default to cover common purchased-assembly patterns (bearing, pulley, idler), or document prominently that callers should always pass an explicit list. There may be no purely structural signal separating a purchased subassembly from an organizational one, which is arguably why Fusion's BOM is a navigable tree rather than a flat list, so an explicit list may be the right design with a better default.
5. Item 1's document guard, reproduced on a READ verb
Independent corroboration of Part A item 1, from a different session and a different verb.
Mid-session the active Fusion tab moved from Wirebening desk v6 to Wire Bender v9 without the caller doing anything to cause it (it shifted while the Manage -> BOM panel was being expanded). The next fusion_assembly_bom call silently returned a completely different assembly: 68 parts / 268 instances instead of 94 / 424, with the desk-frame fasteners absent. Nothing in the response indicated the target had changed.
No data was harmed because the verb is read-only, but it is the same hole: app.activeDocument retargeted underneath the caller. It suggests the expectDocument assertion is worth having on read verbs too, not only mutating ones, since a silently wrong BOM is easy to act on and hard to notice.