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.
Getting component libraries into Fusion - findings log
Hard-won findings from cracking "attach the real 3D chip to a Fusion library package." Captured as we go so the final MAKING_LIBRARIES.md + fusion-libraries skill are complete and correct. Newest insight at the bottom of each section.
1. Use chip-fetcher's curated LIBRARY, not a raw /tmp download
chip-fetcher/library/<MPN>/ is curated and carries variant-specific files. For Fusion, the right
inputs are the .fusion variant (generated by Adom's adom-sfconvert), paired with the curated
named 3D:
| File | Use |
|---|---|
<MPN>.fusion.kicad_sym |
symbol, Fusion-tuned -> feed to adom-lbr |
<MPN>.fusion.kicad_mod |
footprint, Fusion-tuned -> feed to adom-lbr |
<MPN>-named.step |
the curated 3D (part number etched on top; oriented). Pair this with the footprint |
<MPN>.kicad_mod / .manufacturer.* / .altium.* |
raw / other-EDA variants, NOT for Fusion |
MISTAKE made + fixed: I first built the .lbr from a raw /tmp/adom-chip-fetcher-*/EAGLE/*.lbr and
the thin 245KB manufacturer.step. That gave a footprint/3D size mismatch. Switching to
.fusion.kicad_mod + -named.step is the fix. (Convention confirmed in chip-fetcher/src/thumbnails.rs:
it builds the lbr with --name <mpn>.fusion from the .fusion files.)

2. adom-lbr is the right tool; pass it the .fusion files
adom-lbr generate --sym <MPN>.fusion.kicad_sym --fp <MPN>.fusion.kicad_mod -o <MPN>.lbr --name <MPN>
then adom-lbr validate <MPN>.lbr. adom-lbr has no 3D/URN flag (it is symbol+footprint only); the 3D
is attached separately in Fusion (sections 4-6). The VENDOR EAGLE .lbr must NOT be fed to
Create3DPackage - it fails Fusion's XML parser ("File doesn't contain valid XML data"); an
adom-lbr-generated .lbr parses fine.
3. Getting the .lbr / .step onto Windows
The pipeline runs in the cloud container; Fusion runs on Windows; there is NO container->Windows push
verb. Serve the files (python3 -m http.server 8931) and pull them with shell_execute +
Invoke-WebRequest -OutFile C:\Users\<user>\adom-lib\.... Build the shell JSON with json.dumps
(Windows paths need \\).
4. Opening the footprint in the 3D viewer (Package3DEnvironment)
fusion_open_lbrthe.lbrso the library document is ACTIVE (required).fusion_execute_text_command {"command":"Electron.Create3DPackage C:/.../<MPN>.lbr"}opens thePackage3DEnvironmentworkspace showing the footprint (green courtyard + pads +>NAME/>VALUE). ERROR if the library is not active: "Please run the command in library document."- Command defs in that env:
Package3DCmd,Package3DCreateCmd,Package3DStop(Stop = FINISH).
5. Placing the real 3D chip via the API (works)
Inside the env, with fusion_run_modeling_script:
d = adsk.fusion.Design.cast(app.activeProduct); root = d.rootComponent
im = app.importManager
im.importToTarget(im.createSTEPImportOptions("C:/.../<MPN>-named.step"), root) # the real body
oc = root.occurrences.item(root.occurrences.count-1)
# auto-orient: rotate the smallest bbox dimension to Z so it lies flat
# (named.step is usually already Z-thin; raw STEP often imports Y-up and needs +90 about X)
The chip imports at correct scale and sits on the footprint.
6. The library-context commands (the proper in-library path)
Enumerating command defs while the library is active surfaced the real in-library commands:
Electron::AddCustom3DModel- opens a design to add a custom 3D model to the selected package.AttachToFootprintCmd- attaches the modeled body to the footprint (this is what maps it back + mints the eagle URN). It is INTERACTIVE (holds the main thread waiting for a footprint-align confirm), so it resists pure-API completion; recover with Escape if it wedges.- also:
Electron::EditCustom3DModel,Electron::PackageFromWeb,Electron::RemoveCustom3DModel.
7. THE URN SCHEME (the crux)
A library .lbr references a 3D package by urn:adsk.eagle:package:NNNNN/V (managed-library scheme),
NOT the urn:adsk.wipprod:... scheme that fusion_aps_upload / save_to_cloud produce. So you
cannot just paste an uploaded-STEP URN into the .lbr. The eagle URN is minted only when Fusion's 3D
Package Generator FINISHes mapped to the package. The .lbr markup (from the EAGLE spec + Autodesk
forum): <packages3d><package3d urn="urn:adsk.eagle:package:N/V" type="model">...</package3d></packages3d>
and the device carries override_package3d_urn / a <package3dinstance package3d_urn="...">.
8. Open item
The one step not yet automated end-to-end: minting + mapping the eagle URN (the FINISH inside the
in-library generator). Current plan: open the footprint env with the chip placed (sections 4-5), let
the human align + FINISH/save once, then export that .lbr, read the exact package3d markup + eagle
URN, and from there automate the edit-and-reupload for every future chip.
9. Integration test (adom-lbr.fusion3d/1 sidecar) - results
Tested the adom-lbr-fixed .lbr + ads.fusion3d.json sidecar end to end:
- Footprint writer fix: VERIFIED. The new
adom-lbr generateemits a real 4-sided LQFP-64 (16 left / 16 right / 16 top / 16 bottom<smd>, X & Y ±5.74 mm), 64<connect>intact. Opens in Fusion as a proper QFP, not a 2-column placeholder. (Format nit: the<smd>have norot=- fine for square pads, but non-square pads on the top/bottom sides would needrot="R90".) - URN minting: the assumed scheme is WRONG. Running the 3D Package Generator
(
Create3DPackage-> import model ->Package3DStop/FINISH -> Save) mintsurn:adsk.wipprod:dm.lineage:...(a regular user cloud design), NOT theurn:adsk.eagle:package:NNN/Vthe manifest expects. Fusion's generator saves a custom 3D model as an ordinary cloud file (wipprod), not a managed eagle package. - Binding the wipprod URN: FAILS. Writing
<packages3d><package3d urn="urn:adsk.wipprod:dm.lineage:...">- a device
<package3dinstance package3d_urn="...">into the.lbrand reopening gives ".lbr has errors and cannot be opened. Close the empty design file..." So a wipprod URN is not valid inpackage3d; the.lbrgenuinely needs anadsk.eagle:packageURN.
- a device
- THE REMAINING BLOCKER: how to mint an
adsk.eagle:packageURN for a custom model. The standalone generator path does not produce one. The in-libraryElectron::AddCustom3DModel+AttachToFootprintCmdpath (section 6) is the likely minter, but it is interactive. This is the crux to crack next.
10. Capturing GUI error dialogs (Fusion) - ALWAYS check owned popups
Fusion error dialogs (e.g. ".lbr has errors and cannot be opened") are owned popups: they do
NOT enumerate in desktop_list_windows and are invisible to a plain capture of the main window. A
fusion_* verb can return success:true while an error dialog is actually up.
desktop_screenshot_window {hwnd} (AD v1.8.177+) captures them automatically and returns them at the
TOP LEVEL: ownedPopupCount (always present; 0 = none) + _screenshots[] (each owned popup:
title, kind:"owned_popup", localSafePath, rect, coordMap). The CLI auto-pulls each popup PNG.
RULE: after every Fusion open / execute_text_command / generator FINISH, grab
desktop_screenshot_window on the Fusion main hwnd and check ownedPopupCount / read the
screenshots[] array (each entry: title, localSafePath, coordMap, shotId; the CLI auto-pulls
each PNG to /tmp/ad-shots/). Do NOT just read output.data.image (that is the main window only and
misses owned dialogs). Treat ownedPopupCount > 0 as "a dialog is up - read each popup before proceeding."
(Field note: _screenshots/_popups_note are doc-strings; the real array is screenshots.)
11. SUCCESS - the WORKING 3D-attach flow (supersedes the section 9 "bind fails" path)
The manual package3d-XML / pre-minted-URN approach (section 9) was a dead end. The generator FINISH,
launched from the open library, DOES bind the 3D to the deviceset - no XML editing, no wipprod URN.
Proven end-to-end on ADS8588SIPM (LQFP-64): the Content Manager tree shows the 3D nested under the
package under the deviceset, the Packages panel's Package column flips from Placeholder to the part
name, and the 3D preview becomes the real chip. This is the first time the full Fusion electronics 3D
attach has been automated through the bridge.


The repeatable sequence (all via existing verbs):
- Build the
.lbrfrom the chip-fetcher.fusionvariant (adom-lbr generate); footprint must be a real 4-sided package (the writer fix). Stage.lbr+ the model STEP to Windows. fusion_open_lbrthe.lbrso the library is the ACTIVE document.fusion_execute_text_command Electron.Create3DPackage <C:/...lbr>-> opensPackage3DEnvironmentshowing the footprint.fusion_run_modeling_script:importManager.importToTarget(createSTEPImportOptions(<C:/...step>), root), then auto-orient (rotate the smallest bbox dim to Z so it lies flat on the footprint).fusion_run_modeling_script:ui.commandDefinitions.itemById("Package3DStop").execute()(FINISH).- A Save dialog appears (owned dialog) ->
desktop_ui_clickitsQTApplication.QTFrameWindow.standardActions.SaveButton. - Back on the library: the deviceset's package now carries the real 3D. The right-panel preview LAGS -
re-grab the window (or click the package in the Content Manager) to see
Package=part-name + the real 3D; the tree is the source of truth, the preview refresh is delayed.
PITFALL corrected: do NOT conclude "it didn't bind" from a stale gray preview right after FINISH - check
the Content Manager tree / the Package column, and re-grab after a moment.
12. GROUND TRUTH - exactly how Fusion bakes the 3D URN into the .lbr
Exported the bound library to .flbr (fusion_export_source with a .flbr extension), which is a
Fusion document ZIP; the EAGLE library XML lives in .../electron.BlobParts/ExtFile<uuid> (24 KB,
<eagle version="9.7.0">). It DOES contain the 3D, and here is the exact markup Fusion writes for a
CUSTOM (user-uploaded) 3D model:
<packages3d>
<package3d name="ADS8588SIPM" urn="" wip_urn="urn:adsk.wipprod:fs.file:vf.<id>?version=1"
locally_modified="yes" type="model">
<description>ADS8588SIPM</description>
<packageinstances><packageinstance name="ADS8588SIPM"/></packageinstances>
</package3d>
</packages3d>
<!-- and inside the matching <device ...>: -->
<package3dinstances>
<package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.<id>?version=1"/>
</package3dinstances>
THE DELTA (why the section-9 manual bind failed):
urn=""is EMPTY for a custom model (theurnslot is for MANAGEDurn:adsk.eagle:package:N/Vcontent only). The actual reference goes inwip_urn=.- The URN form is the versioned file URN
urn:adsk.wipprod:fs.file:vf.<id>?version=1, NOT thedm.lineageform. (fusion_aps_upload/save_to_cloudreturn adm.lineagelineage URN; the?version=1file URN is the one to use - get it fromfusion_aps_file_info/the saved version.) - Add
locally_modified="yes"andtype="model". - The device's
<package3dinstance package3d_urn="...">uses the SAMEfs.file:vf...?version=1form.
So the manifest's adsk.eagle:package assumption is only for managed-library parts; for a
self-uploaded model the binding is a wip_urn (fs.file:vf) with empty urn. With this exact shape,
adom-lbr (or the bridge) CAN write the binding directly given the model's versioned file URN - no
generator UI needed. (The generator FINISH path also works and is what produced this reference.)
13. Resolved sidecar contract (answers to adom-lbr v1.1.1)
Q: what does the sidecar ship for the FINISH path? Just model.path + package + placement.
That is sufficient - the bridge does Create3DPackage -> import -> orient -> FINISH -> Save. placement
stays useful as an orientation hint/override (the bridge's auto-orient is "rotate smallest bbox dim to Z";
a known pin-1 rotation/offset in placement lets adom-lbr override it when a part needs it).
Q: write the minted wip_urn back to the sidecar (status -> bound)? YES, record it - for idempotency
(re-runs detect "already bound"), provenance (which model version), and to enable the offline bind-3d
fast-path later. BUT the in-Fusion library is the runtime source of truth; the sidecar record is
bookkeeping that adom-lbr owns + writes. The bridge's part is to REPORT the minted URN: after the
Save, fusion_aps_file_info {query:"<package>"} returns the saved 3D-package design's tip
fs.file:vf.<id>?version=N URN - adom-lbr writes that into the sidecar (urn, urn_status:"bound").
Q: dm.lineage vs fs.file in the .lbr? ONLY the versioned fs.file:vf.<id>?version=N goes in the
.lbr - in both wip_urn= and the device package3d_urn=. NEVER dm.lineage in the .lbr (Fusion pins
a specific version, consistent with locally_modified="yes"). dm.lineage is the stable cross-version ID;
keep it (optionally) only as SIDECAR provenance for re-resolving the latest version, never in the binding.
# Getting component libraries into Fusion - findings log
Hard-won findings from cracking "attach the real 3D chip to a Fusion library package." Captured as we
go so the final MAKING_LIBRARIES.md + fusion-libraries skill are complete and correct. Newest insight
at the bottom of each section.
## 1. Use chip-fetcher's curated LIBRARY, not a raw /tmp download
`chip-fetcher/library/<MPN>/` is curated and carries **variant-specific** files. For Fusion, the right
inputs are the **`.fusion`** variant (generated by Adom's `adom-sfconvert`), paired with the curated
named 3D:
| File | Use |
|---|---|
| `<MPN>.fusion.kicad_sym` | symbol, Fusion-tuned -> feed to adom-lbr |
| `<MPN>.fusion.kicad_mod` | footprint, Fusion-tuned -> feed to adom-lbr |
| `<MPN>-named.step` | the curated 3D (part number etched on top; oriented). Pair this with the footprint |
| `<MPN>.kicad_mod` / `.manufacturer.*` / `.altium.*` | raw / other-EDA variants, NOT for Fusion |
MISTAKE made + fixed: I first built the `.lbr` from a raw `/tmp/adom-chip-fetcher-*/EAGLE/*.lbr` and
the thin 245KB `manufacturer.step`. That gave a footprint/3D size mismatch. Switching to
`.fusion.kicad_mod` + `-named.step` is the fix. (Convention confirmed in `chip-fetcher/src/thumbnails.rs`:
it builds the lbr with `--name <mpn>.fusion` from the `.fusion` files.)

## 2. adom-lbr is the right tool; pass it the .fusion files
`adom-lbr generate --sym <MPN>.fusion.kicad_sym --fp <MPN>.fusion.kicad_mod -o <MPN>.lbr --name <MPN>`
then `adom-lbr validate <MPN>.lbr`. adom-lbr has no 3D/URN flag (it is symbol+footprint only); the 3D
is attached separately in Fusion (sections 4-6). The VENDOR EAGLE `.lbr` must NOT be fed to
`Create3DPackage` - it fails Fusion's XML parser ("File doesn't contain valid XML data"); an
adom-lbr-generated `.lbr` parses fine.
## 3. Getting the .lbr / .step onto Windows
The pipeline runs in the cloud container; Fusion runs on Windows; there is NO container->Windows push
verb. Serve the files (`python3 -m http.server 8931`) and pull them with `shell_execute` +
`Invoke-WebRequest -OutFile C:\Users\<user>\adom-lib\...`. Build the shell JSON with `json.dumps`
(Windows paths need `\\`).
## 4. Opening the footprint in the 3D viewer (Package3DEnvironment)
- `fusion_open_lbr` the `.lbr` so the **library document is ACTIVE** (required).
- `fusion_execute_text_command {"command":"Electron.Create3DPackage C:/.../<MPN>.lbr"}` opens the
**`Package3DEnvironment`** workspace showing the footprint (green courtyard + pads + `>NAME`/`>VALUE`).
ERROR if the library is not active: "Please run the command in library document."
- Command defs in that env: `Package3DCmd`, `Package3DCreateCmd`, `Package3DStop` (Stop = FINISH).
## 5. Placing the real 3D chip via the API (works)
Inside the env, with `fusion_run_modeling_script`:
```python
d = adsk.fusion.Design.cast(app.activeProduct); root = d.rootComponent
im = app.importManager
im.importToTarget(im.createSTEPImportOptions("C:/.../<MPN>-named.step"), root) # the real body
oc = root.occurrences.item(root.occurrences.count-1)
# auto-orient: rotate the smallest bbox dimension to Z so it lies flat
# (named.step is usually already Z-thin; raw STEP often imports Y-up and needs +90 about X)
```
The chip imports at correct scale and sits on the footprint.
## 6. The library-context commands (the proper in-library path)
Enumerating command defs while the **library** is active surfaced the real in-library commands:
- `Electron::AddCustom3DModel` - opens a design to add a custom 3D model to the selected package.
- `AttachToFootprintCmd` - attaches the modeled body to the footprint (this is what maps it back +
mints the eagle URN). It is INTERACTIVE (holds the main thread waiting for a footprint-align confirm),
so it resists pure-API completion; recover with Escape if it wedges.
- also: `Electron::EditCustom3DModel`, `Electron::PackageFromWeb`, `Electron::RemoveCustom3DModel`.
## 7. THE URN SCHEME (the crux)
A library `.lbr` references a 3D package by **`urn:adsk.eagle:package:NNNNN/V`** (managed-library scheme),
NOT the **`urn:adsk.wipprod:...`** scheme that `fusion_aps_upload` / `save_to_cloud` produce. So you
cannot just paste an uploaded-STEP URN into the `.lbr`. The eagle URN is minted only when Fusion's 3D
Package Generator FINISHes mapped to the package. The `.lbr` markup (from the EAGLE spec + Autodesk
forum): `<packages3d><package3d urn="urn:adsk.eagle:package:N/V" type="model">...</package3d></packages3d>`
and the device carries `override_package3d_urn` / a `<package3dinstance package3d_urn="...">`.
## 8. Open item
The one step not yet automated end-to-end: minting + mapping the eagle URN (the FINISH inside the
in-library generator). Current plan: open the footprint env with the chip placed (sections 4-5), let
the human align + FINISH/save once, then export that `.lbr`, read the exact `package3d` markup + eagle
URN, and from there automate the edit-and-reupload for every future chip.
## 9. Integration test (adom-lbr.fusion3d/1 sidecar) - results
Tested the adom-lbr-fixed `.lbr` + `ads.fusion3d.json` sidecar end to end:
- **Footprint writer fix: VERIFIED.** The new `adom-lbr generate` emits a real 4-sided LQFP-64
(16 left / 16 right / 16 top / 16 bottom `<smd>`, X & Y ±5.74 mm), 64 `<connect>` intact. Opens in
Fusion as a proper QFP, not a 2-column placeholder. (Format nit: the `<smd>` have **no `rot=`** - fine
for square pads, but non-square pads on the top/bottom sides would need `rot="R90"`.)
- **URN minting: the assumed scheme is WRONG.** Running the 3D Package Generator
(`Create3DPackage` -> import model -> `Package3DStop`/FINISH -> Save) mints
**`urn:adsk.wipprod:dm.lineage:...`** (a regular user cloud design), NOT the
**`urn:adsk.eagle:package:NNN/V`** the manifest expects. Fusion's generator saves a *custom* 3D model
as an ordinary cloud file (wipprod), not a managed eagle package.
- **Binding the wipprod URN: FAILS.** Writing `<packages3d><package3d urn="urn:adsk.wipprod:dm.lineage:...">`
+ a device `<package3dinstance package3d_urn="...">` into the `.lbr` and reopening gives
**"<file>.lbr has errors and cannot be opened. Close the empty design file..."** So a wipprod URN is
not valid in `package3d`; the `.lbr` genuinely needs an `adsk.eagle:package` URN.
- **THE REMAINING BLOCKER:** how to mint an `adsk.eagle:package` URN for a custom model. The standalone
generator path does not produce one. The in-library `Electron::AddCustom3DModel` + `AttachToFootprintCmd`
path (section 6) is the likely minter, but it is interactive. This is the crux to crack next.
## 10. Capturing GUI error dialogs (Fusion) - ALWAYS check owned popups
Fusion error dialogs (e.g. "<file>.lbr has errors and cannot be opened") are **owned popups**: they do
NOT enumerate in `desktop_list_windows` and are invisible to a plain capture of the main window. A
`fusion_*` verb can return `success:true` while an error dialog is actually up.
**`desktop_screenshot_window {hwnd}` (AD v1.8.177+) captures them automatically** and returns them at the
TOP LEVEL: **`ownedPopupCount`** (always present; 0 = none) + **`_screenshots[]`** (each owned popup:
`title`, `kind:"owned_popup"`, `localSafePath`, `rect`, `coordMap`). The CLI auto-pulls each popup PNG.
RULE: after every Fusion open / `execute_text_command` / generator FINISH, grab
`desktop_screenshot_window` on the Fusion main hwnd and **check `ownedPopupCount` / read the
`screenshots[]` array** (each entry: `title`, `localSafePath`, `coordMap`, `shotId`; the CLI auto-pulls
each PNG to `/tmp/ad-shots/`). Do NOT just read `output.data.image` (that is the main window only and
misses owned dialogs). Treat `ownedPopupCount > 0` as "a dialog is up - read each popup before proceeding."
(Field note: `_screenshots`/`_popups_note` are doc-strings; the real array is `screenshots`.)
## 11. SUCCESS - the WORKING 3D-attach flow (supersedes the section 9 "bind fails" path)
The manual `package3d`-XML / pre-minted-URN approach (section 9) was a dead end. The **generator FINISH,
launched from the open library, DOES bind the 3D to the deviceset** - no XML editing, no wipprod URN.
Proven end-to-end on ADS8588SIPM (LQFP-64): the Content Manager tree shows the 3D nested under the
package under the deviceset, the Packages panel's `Package` column flips from `Placeholder` to the part
name, and the 3D preview becomes the real chip. **This is the first time the full Fusion electronics 3D
attach has been automated through the bridge.**


The repeatable sequence (all via existing verbs):
1. Build the `.lbr` from the chip-fetcher **`.fusion`** variant (`adom-lbr generate`); footprint must be a
real 4-sided package (the writer fix). Stage `.lbr` + the model STEP to Windows.
2. `fusion_open_lbr` the `.lbr` so the **library is the ACTIVE document**.
3. `fusion_execute_text_command Electron.Create3DPackage <C:/...lbr>` -> opens `Package3DEnvironment`
showing the footprint.
4. `fusion_run_modeling_script`: `importManager.importToTarget(createSTEPImportOptions(<C:/...step>), root)`,
then auto-orient (rotate the smallest bbox dim to Z so it lies flat on the footprint).
5. `fusion_run_modeling_script`: `ui.commandDefinitions.itemById("Package3DStop").execute()` (FINISH).
6. A **Save** dialog appears (owned dialog) -> `desktop_ui_click` its
`QTApplication.QTFrameWindow.standardActions.SaveButton`.
7. Back on the library: the deviceset's package now carries the real 3D. **The right-panel preview LAGS** -
re-grab the window (or click the package in the Content Manager) to see `Package`=part-name + the real
3D; the tree is the source of truth, the preview refresh is delayed.
PITFALL corrected: do NOT conclude "it didn't bind" from a stale gray preview right after FINISH - check
the Content Manager tree / the `Package` column, and re-grab after a moment.
## 12. GROUND TRUTH - exactly how Fusion bakes the 3D URN into the .lbr
Exported the bound library to `.flbr` (`fusion_export_source` with a `.flbr` extension), which is a
Fusion document ZIP; the EAGLE library XML lives in `.../electron.BlobParts/ExtFile<uuid>` (24 KB,
`<eagle version="9.7.0">`). It DOES contain the 3D, and here is the exact markup Fusion writes for a
CUSTOM (user-uploaded) 3D model:
```xml
<packages3d>
<package3d name="ADS8588SIPM" urn="" wip_urn="urn:adsk.wipprod:fs.file:vf.<id>?version=1"
locally_modified="yes" type="model">
<description>ADS8588SIPM</description>
<packageinstances><packageinstance name="ADS8588SIPM"/></packageinstances>
</package3d>
</packages3d>
<!-- and inside the matching <device ...>: -->
<package3dinstances>
<package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.<id>?version=1"/>
</package3dinstances>
```
THE DELTA (why the section-9 manual bind failed):
- `urn=""` is **EMPTY** for a custom model (the `urn` slot is for MANAGED `urn:adsk.eagle:package:N/V`
content only). The actual reference goes in **`wip_urn=`**.
- The URN form is the **versioned file URN** `urn:adsk.wipprod:fs.file:vf.<id>?version=1`, NOT the
`dm.lineage` form. (`fusion_aps_upload`/`save_to_cloud` return a `dm.lineage` lineage URN; the
`?version=1` file URN is the one to use - get it from `fusion_aps_file_info`/the saved version.)
- Add **`locally_modified="yes"`** and `type="model"`.
- The device's `<package3dinstance package3d_urn="...">` uses the SAME `fs.file:vf...?version=1` form.
So the manifest's `adsk.eagle:package` assumption is only for managed-library parts; for a
self-uploaded model the binding is a `wip_urn` (fs.file:vf) with empty `urn`. With this exact shape,
adom-lbr (or the bridge) CAN write the binding directly given the model's versioned file URN - no
generator UI needed. (The generator FINISH path also works and is what produced this reference.)
## 13. Resolved sidecar contract (answers to adom-lbr v1.1.1)
**Q: what does the sidecar ship for the FINISH path?** Just `model.path` + `package` + `placement`.
That is sufficient - the bridge does Create3DPackage -> import -> orient -> FINISH -> Save. `placement`
stays useful as an orientation hint/override (the bridge's auto-orient is "rotate smallest bbox dim to Z";
a known pin-1 rotation/offset in `placement` lets adom-lbr override it when a part needs it).
**Q: write the minted wip_urn back to the sidecar (status -> bound)?** YES, record it - for idempotency
(re-runs detect "already bound"), provenance (which model version), and to enable the offline `bind-3d`
fast-path later. BUT the **in-Fusion library is the runtime source of truth**; the sidecar record is
bookkeeping that **adom-lbr owns + writes**. The bridge's part is to REPORT the minted URN: after the
Save, `fusion_aps_file_info {query:"<package>"}` returns the saved 3D-package design's tip
**`fs.file:vf.<id>?version=N`** URN - adom-lbr writes that into the sidecar (`urn`, `urn_status:"bound"`).
**Q: dm.lineage vs fs.file in the .lbr?** ONLY the versioned **`fs.file:vf.<id>?version=N`** goes in the
`.lbr` - in both `wip_urn=` and the device `package3d_urn=`. NEVER `dm.lineage` in the `.lbr` (Fusion pins
a specific version, consistent with `locally_modified="yes"`). `dm.lineage` is the stable cross-version ID;
keep it (optionally) only as SIDECAR provenance for re-resolving the latest version, never in the binding.