Adom Desktop - Fusion 360 Bridge
Public Made by Adomby adom
Drive Autodesk Fusion 360 from the cloud via Adom Desktop: component libraries, IPC package generation, board layout, exports (STEP/Gerbers/BOM/CPL), fast APS cloud search, and parametric modeling.
name: fusion-driving description: How to SAFELY drive Fusion 360 through the Adom bridge across many steps without losing work - the discipline of reading the screenshot/owned-popup ARRAY after every mutating op and ANALYZING any dialog BEFORE the next step, never blind-dismissing, and never fullscreen-capturing (it forces foreground and disrupts the user). Includes the blocking-dialog catalog with the CORRECT response for each, and how the bridge now returns the dialog array + an analyze-this hint automatically. Read this BEFORE running any multi-step Fusion automation (attaching 3D, saving libraries, closing docs, modeling scripts). Trigger words - drive fusion, fusion dialog, blocking dialog, are you sure you want to close, packages are being uploaded, save was cancelled, ownedPopupCount, screenshot array, owned popups, fusion notification, lower right error, dismiss dialog, fusion modal, fusion_screenshot_all, fusion_window_info, fusion_check_dialogs, fullscreen capture fusion, analyze before proceeding.
Driving Fusion 360 safely (read the popup array, never fly blind)
Fusion is a desktop app you are operating headlessly. Almost any mutating operation can pop a modal dialog or a notification you cannot see unless you look - and if you barrel ahead (or blind-dismiss), you destroy work. This skill is the operating discipline that keeps that from happening. It is the foundation under fusion-libraries, fusion-multipart-libraries, and fusion-cloud-save.
⛔ The cautionary tale (why this skill exists, 2026-06-28)
Building a 10-part library, the loop force-closed generator docs that were still uploading 3D
packages to the Fusion Hub. Fusion popped "Packages are being uploaded... if you close you will
lose these changes. Are you sure you want to close?" The automation was sleeping through a blind
dismiss_blocking_dialogs loop, which clicked straight through it - closing the library before it
ever saved. All 10 attaches were lost. Every rule below is the fix for one beat of that failure.
Rule 1 - after EVERY mutating op, READ the popup array. Then analyze. Then proceed.
A mutating op = anything that changes Fusion's state: fusion_run_modeling_script,
fusion_execute_text_command, fusion_close_document, fusion_close_all_documents,
fusion_save_lbr, fusion_attach_3d_package, fusion_open_lbr, any export, any electron_run
that writes.
After it returns, you MUST inspect what owned popups are now up before doing the next step. Three ways to get the array, in order of preference:
- The bridge does it for you (default). Mutating
fusion_*verbs now returndialogsDetected, adialogs[]array (each withtitle,category,resolution, and ascreenshotpath you can Read), and a top-level_hint. When `dialogsDetected > 0, STOP and analyze the dialogs[] before your next call. Never ignore that hint. (See "How the bridge enforces this" below.) fusion_screenshot_all- captures the main window PLUS every Qt dialog window as separate shots, and returns the list of saved paths. Read each.desktop_screenshot_window {"hwnd": <fusion-hwnd>}(AD core) - returnsscreenshots[]andownedPopupCount.ownedPopupCount > 0means dialogs are stacked on the window. Read the shots. Get the hwnd fromfusion_window_info(itshwndfield) ordesktop_find_window {"titleContains":"Autodesk Fusion"}.
To actually SEE a shot - mind WHERE it lands:
- AD core
desktop_screenshot_window {hwnd}saves the PNG into your container (e.g./tmp/adom-desktop-screenshots/) - Read it directly. - The bridge's own captures (the auto
dialogArray[].screenshotpaths andfusion_screenshot_all) are saved on the Windows box (C:/tmp/conduit-screenshots/). To see one, either re-capture that hwnd withdesktop_screenshot_window {hwnd}(lands in your container) ordesktop_pull_fileit over.
Either way, LOOK - do not describe it from memory.
Rule 2 - NEVER fullscreen-capture. Always target the window by hwnd.
- ⛔ Do NOT use
desktop_screenshot_screen(whole-desktop capture). It grabs whatever is in the foreground (often the user's browser, not Fusion), and screen-DC capture paths force the target toward the foreground - which disrupts the user, who may be doing something else. It also routinely captures the WRONG window. - ✅ Always capture a specific
hwnd(fusion_screenshot_all,fusion_screenshot_fusion,desktop_screenshot_window {hwnd}). These usePrintWindow/ WGC and capture the exact window in the BACKGROUND without bringing it forward. Fusion keeps running behind whatever the user is doing. This is the only acceptable way to look at Fusion.
Rule 3 - NEVER blind-dismiss. Classify first, then choose the RIGHT action.
A dialog has a correct answer that depends on what it says. Clicking the default can be catastrophic (clicking "Yes" on "sure you want to close, you'll lose changes?" = data loss). So:
- Identify the dialog (the
category/resolutionfromdialogs[], or Read its screenshot). - Choose the action that PRESERVES work, from the catalog below.
- Only use a generic dismiss as a LAST resort, and only for dialogs you have confirmed are safe to cancel/escape.
To act on a specific dialog, target its hwnd: fusion_click_fusion {"hwnd":<dlg>, ...},
fusion_send_key {"hwnd":<dlg>, "key":"escape"}, or fusion_close_window {"hwnd":<dlg>}.
⛔ Dismiss in the BACKGROUND - close_window (WM_CLOSE), NEVER send_key/Escape
When you DO dismiss a dialog, use fusion_close_window {"hwnd":<dlg>} (WM_CLOSE via PostMessage =
Cancel/No). It dismisses without stealing focus. ⛔ Do NOT use fusion_send_key/Escape to expire
a dialog - send_key calls SetForegroundWindow and YANKS Fusion to the foreground, disrupting
the user (caught 2026-06-29: an Escape pulled Fusion to the front mid-task). WM_CLOSE is also more
reliable than Escape on Qt dialogs. The bridge's own auto-dismiss paths (_dismiss_dialogs_bg, the
long-command pre-dismiss) all use close_window for exactly this reason. Background screenshots +
background dismiss = the user never sees Fusion jump around.
The blocking-dialog catalog (title substring -> what it means -> do THIS)
| Dialog (title/body contains) | Meaning | Correct response |
|---|---|---|
| "packages are being uploaded", "lose these changes", "are you sure you want to close" | A doc is closing while 3D packages still upload to the Hub. Closing = lose the packages + unsaved bindings. | Click No. WAIT and poll until the upload finishes (see fusion-cloud-save), THEN close/save. NEVER click Yes. |
| "cannot be saved while packages are being uploaded", "save was cancelled" | You tried saveAs mid-upload; Fusion refused. | Not fatal. Wait for the Hub upload to finish, then retry the saveAs (poll past it). |
| "needs to update", "update is available", "software update" | Fusion wants to self-update. | Do NOT auto-confirm (it can update mid-automation). Clear on the desktop or let it finish, then retry. A pending update also causes add-in/host version-drift crashes. |
| "select electronics design", "linked to multiple" | A file links to multiple electronics designs; CEF picker. | Its list is NOT Win32/keyboard navigable. Open the specific design by URN/API instead, or select on the desktop. See fusion-electronics. |
| "recovery", "recover unsaved", "document recovery" | Document Recovery prompt. | fusion_dismiss_recovery, or fusion_relocate_recovery BEFORE fusion_start to prevent it. |
| "save changes", "unsaved changes", "do you want to save" | Unsaved-changes prompt on close. | Use fusion_close_document (closes without the save modal). Only Escape/Cancel if you mean to keep editing. |
| "what do you want to design" | Fusion's start picker (no doc open). | fusion_send_key {"key":"escape"}. |
| "create new symbol/footprint/device ''?" | An EDIT <name>.sym/.pac/.dev was run with a name Fusion can't find as that object - usually a DEVICESET name passed to .sym/.pac whose symbol/package is named by the shared combo (e.g. R-0603, not R-0603-10K). |
Dismiss in the BACKGROUND (fusion_close_window {hwnd} = No - never create a stray). Then re-EDIT with the correct symbol/package name. fusion_capture_library_views now auto-handles this. |
| bare "Fusion360" modal during an open | Usually the linked-design picker. | fusion_screenshot_fusion to confirm, then handle as the picker. |
(The bridge classifies these in handlers/dialog_classify.py. When you discover a new one, add a
rule there with its correct response so every future session handles it right.)
Rule 4 - the lower-right notification tray (errors/warnings you keep missing)
Fusion shows non-modal toasts in the lower-right ("1 warning(s), 1 error(s)..."). They are NOT modal dialogs, so dialog enumeration may not flag them - but they tell you an operation half-failed. They DO render in an hwnd-targeted main-window screenshot. So after a risky op, also glance at the main-window shot's lower-right, not just the popup array. If you see an error count, open the notification center and read it before continuing.
Rule 5 - don't DESTABILIZE Fusion (it crashes more easily than you think)
Long automation runs take Fusion DOWN if you abuse it - learned the hard way over a multi-hour run where Fusion died repeatedly. The culprits:
- Blanket "close all documents" loops (
while app.documents.count>0: app.documents.item(0).close(False)) run before every op to "reset state". This churns Fusion hard and can crash it or leave it wedged. Close ONLY what you need (fusion_close_document, or close the one stray doc), never everything. - Back-to-back heavy operations - import + saveAs + Create3DPackage in a tight loop, dozens of
times, plus repeated
bridge_installrespawns - destabilize the session.
So: minimize document churn, do NOT reset-by-closing-everything, save your work to the cloud as you go
(fusion-cloud-save) and reopen from the cloud after a reset (the
in-session view is often wedged). After a bridge_install respawn Fusion can report "not running"
even when the process is alive - a fusion_start re-establishes the connection. And if Fusion dies
mid-run, that was almost certainly YOU, not the user - own it, don't blame them.
How the bridge enforces this (so you cannot miss it)
_post_open_screenshot() has always auto-captured the main window + every dialog after open
commands and told the AI to read them. That same capture now fires after all mutating verbs via
_capture_dialog_array(), which:
- cheaply enumerates dialog windows (
get_fusion_window_info, a Win32EnumWindows- no screenshot when nothing is up), - suppresses false positives: a docked panel (Browser/Timeline) shares the "Fusion360" title and can
slip past the size filter, but it does NOT disable the main window. So a generic-titled candidate is
only surfaced when the main window is actually disabled (
mainWindowEnabled:false- a real modal is up) or it matches a known dialog by title. That keeps the hint from crying wolf on every op, - on detection, classifies each (
classify_blocking_dialogs) and screenshots it by hwnd (screenshot_hwnd, backgroundPrintWindow), - returns
dialogsDetected+dialogs[]+ a top-level_hintthat says ANALYZE these before proceeding; do NOT blind-dismiss.
You can also call fusion_check_dialogs at any time to get the current array on demand (e.g.
while polling a long upload). The point: the array and the hint come back to you automatically - your
job is to actually READ them and act, every time.
The loop that should be muscle memory
do mutating op
-> read dialogsDetected / dialogs[] / ownedPopupCount in the response (or fusion_check_dialogs)
-> if a dialog is up: Read its screenshot, look it up in the catalog, take the work-preserving action
-> glance at the main-window shot's lower-right for an error toast
-> only then do the next op
Slow is smooth, smooth is fast. The one time you skip the look is the time you lose the library.
---
name: fusion-driving
description: How to SAFELY drive Fusion 360 through the Adom bridge across many steps without losing work - the discipline of reading the screenshot/owned-popup ARRAY after every mutating op and ANALYZING any dialog BEFORE the next step, never blind-dismissing, and never fullscreen-capturing (it forces foreground and disrupts the user). Includes the blocking-dialog catalog with the CORRECT response for each, and how the bridge now returns the dialog array + an analyze-this hint automatically. Read this BEFORE running any multi-step Fusion automation (attaching 3D, saving libraries, closing docs, modeling scripts). Trigger words - drive fusion, fusion dialog, blocking dialog, are you sure you want to close, packages are being uploaded, save was cancelled, ownedPopupCount, screenshot array, owned popups, fusion notification, lower right error, dismiss dialog, fusion modal, fusion_screenshot_all, fusion_window_info, fusion_check_dialogs, fullscreen capture fusion, analyze before proceeding.
---
# Driving Fusion 360 safely (read the popup array, never fly blind)
Fusion is a desktop app you are operating headlessly. **Almost any mutating operation can pop a
modal dialog or a notification you cannot see unless you look** - and if you barrel ahead (or
blind-dismiss), you destroy work. This skill is the operating discipline that keeps that from
happening. It is the foundation under [fusion-libraries](../fusion-libraries/SKILL.md),
[fusion-multipart-libraries](../fusion-multipart-libraries/SKILL.md), and
[fusion-cloud-save](../fusion-cloud-save/SKILL.md).
## ⛔ The cautionary tale (why this skill exists, 2026-06-28)
Building a 10-part library, the loop force-closed generator docs that were **still uploading 3D
packages to the Fusion Hub**. Fusion popped *"Packages are being uploaded... if you close you will
lose these changes. Are you sure you want to close?"* The automation was sleeping through a blind
`dismiss_blocking_dialogs` loop, which clicked straight through it - **closing the library before it
ever saved. All 10 attaches were lost.** Every rule below is the fix for one beat of that failure.
## Rule 1 - after EVERY mutating op, READ the popup array. Then analyze. Then proceed.
A mutating op = anything that changes Fusion's state: `fusion_run_modeling_script`,
`fusion_execute_text_command`, `fusion_close_document`, `fusion_close_all_documents`,
`fusion_save_lbr`, `fusion_attach_3d_package`, `fusion_open_lbr`, any export, any `electron_run`
that writes.
After it returns, you MUST inspect what owned popups are now up before doing the next step. Three
ways to get the array, in order of preference:
1. **The bridge does it for you (default).** Mutating `fusion_*` verbs now return
`dialogsDetected`, a `dialogs[]` array (each with `title`, `category`, `resolution`, and a
`screenshot` path you can Read), and a top-level `_hint`. **When `dialogsDetected > 0, STOP and
analyze the dialogs[] before your next call.** Never ignore that hint. (See "How the bridge
enforces this" below.)
2. **`fusion_screenshot_all`** - captures the main window PLUS every Qt dialog window as separate
shots, and returns the list of saved paths. Read each.
3. **`desktop_screenshot_window {"hwnd": <fusion-hwnd>}`** (AD core) - returns `screenshots[]` and
**`ownedPopupCount`**. `ownedPopupCount > 0` means dialogs are stacked on the window. Read the
shots. Get the hwnd from `fusion_window_info` (its `hwnd` field) or `desktop_find_window
{"titleContains":"Autodesk Fusion"}`.
**To actually SEE a shot - mind WHERE it lands:**
- AD core `desktop_screenshot_window {hwnd}` saves the PNG **into your container** (e.g.
`/tmp/adom-desktop-screenshots/`) - Read it directly.
- The bridge's own captures (the auto `dialogArray[].screenshot` paths and `fusion_screenshot_all`)
are saved on the **Windows box** (`C:/tmp/conduit-screenshots/`). To see one, either re-capture that
hwnd with `desktop_screenshot_window {hwnd}` (lands in your container) or `desktop_pull_file` it over.
Either way, LOOK - do not describe it from memory.
## Rule 2 - NEVER fullscreen-capture. Always target the window by hwnd.
- ⛔ **Do NOT use `desktop_screenshot_screen`** (whole-desktop capture). It grabs whatever is in the
foreground (often the user's browser, not Fusion), and screen-DC capture paths force the target
toward the foreground - **which disrupts the user, who may be doing something else.** It also
routinely captures the WRONG window.
- ✅ **Always capture a specific `hwnd`** (`fusion_screenshot_all`, `fusion_screenshot_fusion`,
`desktop_screenshot_window {hwnd}`). These use `PrintWindow` / WGC and capture the **exact window
in the BACKGROUND** without bringing it forward. Fusion keeps running behind whatever the user is
doing. This is the only acceptable way to look at Fusion.
## Rule 3 - NEVER blind-dismiss. Classify first, then choose the RIGHT action.
A dialog has a correct answer that depends on what it says. Clicking the default can be catastrophic
(clicking "Yes" on *"sure you want to close, you'll lose changes?"* = data loss). So:
1. Identify the dialog (the `category`/`resolution` from `dialogs[]`, or Read its screenshot).
2. Choose the action that PRESERVES work, from the catalog below.
3. Only use a generic dismiss as a LAST resort, and only for dialogs you have confirmed are safe to
cancel/escape.
To act on a specific dialog, target its `hwnd`: `fusion_click_fusion {"hwnd":<dlg>, ...}`,
`fusion_send_key {"hwnd":<dlg>, "key":"escape"}`, or `fusion_close_window {"hwnd":<dlg>}`.
### ⛔ Dismiss in the BACKGROUND - `close_window` (WM_CLOSE), NEVER `send_key`/Escape
When you DO dismiss a dialog, use **`fusion_close_window {"hwnd":<dlg>}`** (WM_CLOSE via PostMessage =
Cancel/No). It dismisses **without stealing focus**. ⛔ **Do NOT use `fusion_send_key`/Escape to expire
a dialog** - `send_key` calls `SetForegroundWindow` and **YANKS Fusion to the foreground**, disrupting
the user (caught 2026-06-29: an Escape pulled Fusion to the front mid-task). WM_CLOSE is also more
reliable than Escape on Qt dialogs. The bridge's own auto-dismiss paths (`_dismiss_dialogs_bg`, the
long-command pre-dismiss) all use `close_window` for exactly this reason. Background screenshots +
background dismiss = the user never sees Fusion jump around.
## The blocking-dialog catalog (title substring -> what it means -> do THIS)
| Dialog (title/body contains) | Meaning | Correct response |
|---|---|---|
| **"packages are being uploaded", "lose these changes", "are you sure you want to close"** | A doc is closing while 3D packages still upload to the Hub. Closing = **lose the packages + unsaved bindings**. | Click **No**. WAIT and poll until the upload finishes (see [fusion-cloud-save](../fusion-cloud-save/SKILL.md)), THEN close/save. NEVER click Yes. |
| **"cannot be saved while packages are being uploaded", "save was cancelled"** | You tried saveAs mid-upload; Fusion refused. | Not fatal. Wait for the Hub upload to finish, then retry the saveAs (poll past it). |
| **"needs to update", "update is available", "software update"** | Fusion wants to self-update. | Do NOT auto-confirm (it can update mid-automation). Clear on the desktop or let it finish, then retry. A pending update also causes add-in/host version-drift crashes. |
| **"select electronics design", "linked to multiple"** | A file links to multiple electronics designs; CEF picker. | Its list is NOT Win32/keyboard navigable. Open the specific design by URN/API instead, or select on the desktop. See [fusion-electronics](../fusion-electronics/SKILL.md). |
| **"recovery", "recover unsaved", "document recovery"** | Document Recovery prompt. | `fusion_dismiss_recovery`, or `fusion_relocate_recovery` BEFORE `fusion_start` to prevent it. |
| **"save changes", "unsaved changes", "do you want to save"** | Unsaved-changes prompt on close. | Use `fusion_close_document` (closes without the save modal). Only Escape/Cancel if you mean to keep editing. |
| **"what do you want to design"** | Fusion's start picker (no doc open). | `fusion_send_key {"key":"escape"}`. |
| **"create new symbol/footprint/device '<name>'?"** | An `EDIT <name>.sym/.pac/.dev` was run with a name Fusion can't find as that object - usually a DEVICESET name passed to `.sym`/`.pac` whose symbol/package is named by the shared combo (e.g. `R-0603`, not `R-0603-10K`). | Dismiss in the BACKGROUND (`fusion_close_window {hwnd}` = No - never create a stray). Then re-`EDIT` with the correct symbol/package name. `fusion_capture_library_views` now auto-handles this. |
| bare **"Fusion360"** modal during an open | Usually the linked-design picker. | `fusion_screenshot_fusion` to confirm, then handle as the picker. |
(The bridge classifies these in `handlers/dialog_classify.py`. When you discover a new one, add a
rule there with its correct response so every future session handles it right.)
## Rule 4 - the lower-right notification tray (errors/warnings you keep missing)
Fusion shows non-modal toasts in the **lower-right** ("1 warning(s), 1 error(s)..."). They are NOT
modal dialogs, so dialog enumeration may not flag them - but they tell you an operation half-failed.
They DO render in an hwnd-targeted main-window screenshot. So after a risky op, also glance at the
main-window shot's lower-right, not just the popup array. If you see an error count, open the
notification center and read it before continuing.
## Rule 5 - don't DESTABILIZE Fusion (it crashes more easily than you think)
Long automation runs take Fusion DOWN if you abuse it - learned the hard way over a multi-hour run
where Fusion died repeatedly. The culprits:
- **Blanket "close all documents" loops** (`while app.documents.count>0: app.documents.item(0).close(False)`)
run before every op to "reset state". This churns Fusion hard and can crash it or leave it wedged.
Close ONLY what you need (`fusion_close_document`, or close the one stray doc), never everything.
- **Back-to-back heavy operations** - import + saveAs + Create3DPackage in a tight loop, dozens of
times, plus repeated `bridge_install` respawns - destabilize the session.
So: minimize document churn, do NOT reset-by-closing-everything, save your work to the cloud as you go
([fusion-cloud-save](../fusion-cloud-save/SKILL.md)) and **reopen from the cloud** after a reset (the
in-session view is often wedged). After a `bridge_install` respawn Fusion can report "not running"
even when the process is alive - a `fusion_start` re-establishes the connection. And if Fusion dies
mid-run, that was almost certainly YOU, not the user - own it, don't blame them.
## How the bridge enforces this (so you cannot miss it)
`_post_open_screenshot()` has always auto-captured the main window + every dialog after *open*
commands and told the AI to read them. That same capture now fires after **all mutating verbs** via
`_capture_dialog_array()`, which:
- cheaply enumerates dialog windows (`get_fusion_window_info`, a Win32 `EnumWindows` - no screenshot
when nothing is up),
- suppresses false positives: a docked panel (Browser/Timeline) shares the "Fusion360" title and can
slip past the size filter, but it does NOT disable the main window. So a generic-titled candidate is
only surfaced when the main window is actually disabled (`mainWindowEnabled:false` - a real modal is
up) or it matches a known dialog by title. That keeps the hint from crying wolf on every op,
- on detection, classifies each (`classify_blocking_dialogs`) and screenshots it by hwnd
(`screenshot_hwnd`, background `PrintWindow`),
- returns `dialogsDetected` + `dialogs[]` + a top-level `_hint` that says **ANALYZE these before
proceeding; do NOT blind-dismiss**.
You can also call **`fusion_check_dialogs`** at any time to get the current array on demand (e.g.
while polling a long upload). The point: the array and the hint come back to you automatically - your
job is to actually READ them and act, every time.
## The loop that should be muscle memory
```
do mutating op
-> read dialogsDetected / dialogs[] / ownedPopupCount in the response (or fusion_check_dialogs)
-> if a dialog is up: Read its screenshot, look it up in the catalog, take the work-preserving action
-> glance at the main-window shot's lower-right for an error toast
-> only then do the next op
```
Slow is smooth, smooth is fast. The one time you skip the look is the time you lose the library.