Skip to content
Open
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
71 changes: 49 additions & 22 deletions .pipelines/v2/sdk_v2-js-pipeline-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ C++, C#, and Python stages.

Out of scope (deferred):

- **Linux ARM64.** Cross-cutting ARM64 work item will add this for C++,
C#, Python, and JS together.
- **npm publishing.** Pipeline produces the `.tgz` as an artifact only.

## Supported platforms
Expand All @@ -28,6 +26,7 @@ Out of scope (deferred):
| Windows x64 | `cpp_build_win_x64` | ✅ | ✅ | |
| Windows ARM64 | `cpp_build_win_arm64` | ✅ | ❌ | Cross-compiled on x64 host |
| Linux x64 | `cpp_build_linux_x64` | ✅ | ✅ | |
| Linux ARM64 | `cpp_build_linux_arm64` | ✅ | ✅ | Native on `onnxruntime-linux-ARM64-CPU-2019`; CPU-only ORT package |
| macOS ARM64 | `cpp_build_osx_arm64` | ✅ | ✅ | Native on AcesShared Sequoia |

## Stage graph
Expand All @@ -38,9 +37,10 @@ compute_version
├── cpp_build_win_x64 ──── js_build_win_x64 ──── js_test_win_x64 ─┐
├── cpp_build_win_arm64 ── js_build_win_arm64 (build-only) ───────┤
├── cpp_build_linux_x64 ── js_build_linux_x64 ── js_test_linux_x64┤
├── cpp_build_linux_arm64 ─ js_build_linux_arm64 ─ js_test_linux_arm64┤
└── cpp_build_osx_arm64 ── js_build_osx_arm64 ── js_test_osx_arm64┘
(all 4 builds) ──> js_pack ──> js-sdk
(all 5 builds) ──> js_pack ──> js-sdk
```

Every `js_build_<rid>` stage also depends on `cpp_build_win_x64` because
Expand All @@ -49,17 +49,20 @@ only by that stage and consumed by every JS build.

## Artifacts

| Stage | Artifact name | Contents |
|------------------------|----------------------------|------------------------------------------------------------------------------------------------|
| `js_build_win_x64` | `js-prebuild-win-x64` | `prebuilds/win32-x64/{foundry_local_node.node, foundry_local_preload.node, foundry_local.dll}` |
| `js_build_win_arm64` | `js-prebuild-win-arm64` | `prebuilds/win32-arm64/{…, foundry_local.dll}` |
| `js_build_linux_x64` | `js-prebuild-linux-x64` | `prebuilds/linux-x64/{…, libfoundry_local.so}` |
| `js_build_osx_arm64` | `js-prebuild-osx-arm64` | `prebuilds/darwin-arm64/{…, libfoundry_local.dylib}` |
| `js_pack` | `js-sdk` | `foundry-local-sdk-<version>.tgz` |
| Stage | Artifact name | Contents |
|---------------------------|-----------------------------|------------------------------------------------------------------------------------------------|
| `js_build_win_x64` | `js-prebuild-win-x64` | `prebuilds/win32-x64/{foundry_local_node.node, foundry_local_preload.node, foundry_local.dll}` |
| `js_build_win_arm64` | `js-prebuild-win-arm64` | `prebuilds/win32-arm64/{…, foundry_local.dll}` |
| `js_build_linux_x64` | `js-prebuild-linux-x64` | `prebuilds/linux-x64/{…, libfoundry_local.so}` |
| `js_build_linux_arm64` | `js-prebuild-linux-arm64` | `prebuilds/linux-arm64/{…, libfoundry_local.so}` |
| `js_build_osx_arm64` | `js-prebuild-osx-arm64` | `prebuilds/darwin-arm64/{…, libfoundry_local.dylib}` |
| `js_pack` | `js-sdk` | `foundry-local-sdk-<version>.tgz` |

Naming convention: artifact names use ADO RIDs (`win-x64`, `osx-arm64`);
in-tarball directories use Node's `${process.platform}-${process.arch}`
(`win32-x64`, `darwin-arm64`) so the runtime addon loader finds them.
Note: `linux-arm64` uses the same key for both ADO RID and the npm tarball
directory (Node's `process.platform` is `"linux"`, `process.arch` is `"arm64"`).

## Build-time native dependencies

Expand Down Expand Up @@ -91,7 +94,8 @@ three env-var overrides:
- `FOUNDRY_LOCAL_PREBUILD_DIR` — forces the `copy_addon_to_prebuilds`
destination. Required on win-arm64 because `print-prebuild-dir.mjs`
otherwise uses the host Node's `process.arch` (x64) and lands the
cross-compiled addon in `prebuilds/win32-x64/`.
cross-compiled addon in `prebuilds/win32-x64/`. Also set on linux-arm64
for consistency (though native builds already resolve the right arch).

All three overrides are real DX wins for external consumers building
the addon themselves against a downloaded native artifact.
Expand All @@ -105,6 +109,14 @@ needs. `FOUNDRY_LOCAL_PREBUILD_DIR` points the addon-copy step at
`prebuilds/win32-arm64/`. No test stage — matches the C# / Python
matrix.

## Linux ARM64: native build + test

Build and test on the `onnxruntime-linux-ARM64-CPU-2019` pool
(`hostArchitecture: arm64`). Same `node-gyp rebuild` path as Linux x64.
`install-native.cjs` selects the CPU-only ORT NuGet package
(`Microsoft.ML.OnnxRuntime.Foundry`) for `linux-arm64` — matching the
C++ native pipeline which also uses CPU-only ORT for ARM64.

## Test stage details

- `NodeTool@0` for Node 20.
Expand All @@ -119,7 +131,7 @@ matrix.

## Pack stage

Runs on a Windows agent (`onnxruntime-Win-CPU-2022`) after all four
Runs on a Windows agent (`onnxruntime-Win-CPU-2022`) after all five
builds. Downloads each `js-prebuild-<rid>` artifact, merges them into
`sdk_v2/js/prebuilds/`, stamps the version via
`npm version <v> --no-git-tag-version --allow-same-version`, builds
Expand All @@ -137,13 +149,14 @@ require routing back to a macOS agent to sign Darwin binaries; signing
per-platform avoids that. The `.tgz` itself is **not signed** — npm has
no equivalent to NuGet package signing.

| Stage | Files signed | ESRP keyCode | Tool |
|------------------------|-------------------------------------------------------------------------------|---------------|-----------------------|
| `js_build_win_x64` | `foundry_local_node.node`, `foundry_local_preload.node`, `foundry_local.dll` | `CP-230012` | SigntoolSign |
| `js_build_win_arm64` | same three Windows files | `CP-230012` | SigntoolSign |
| `js_build_osx_arm64` | both `.node` files + `libfoundry_local.dylib` | `CP-401337` | `MacAppDeveloperSign` (placeholder — confirm against ESRP policy on first run) |
| `js_build_linux_x64` | none | n/a | Linux `.so` has no standard signing |
| `js_pack` | none | n/a | `.tgz` not signed by npm convention |
| Stage | Files signed | ESRP keyCode | Tool |
|---------------------------|-------------------------------------------------------------------------------|---------------|-----------------------|
| `js_build_win_x64` | `foundry_local_node.node`, `foundry_local_preload.node`, `foundry_local.dll` | `CP-230012` | SigntoolSign |
| `js_build_win_arm64` | same three Windows files | `CP-230012` | SigntoolSign |
| `js_build_osx_arm64` | both `.node` files + `libfoundry_local.dylib` | `CP-401337` | `MacAppDeveloperSign` (placeholder — confirm against ESRP policy on first run) |
| `js_build_linux_x64` | none | n/a | Linux `.so` has no standard signing |
| `js_build_linux_arm64` | none | n/a | Linux `.so` has no standard signing |
| `js_pack` | none | n/a | `.tgz` not signed by npm convention |

Windows signing block is a near-copy of the SDK DLL signing step in
[`steps-build-cs.yml`](templates/steps-build-cs.yml) — same
Expand Down Expand Up @@ -173,6 +186,19 @@ shape.
`FOUNDRY_LOCAL_PREBUILD_DIR` (added for win-arm64 cross-compile).
- `.gitignore` — negation rule preserving `sdk_v2/js/package-lock.json`
past the repo-wide lockfile ignore.
- `stages-js.yml` — added `js_build_linux_arm64` and `js_test_linux_arm64`
stages; updated `js_pack` dependsOn and artifact inputs to include
`js-prebuild-linux-arm64`.
- `steps-build-js.yml` — added `linux-arm64` to `rid` values; added
`Set prebuild directory (linux-arm64)` bash step; expanded Linux/macOS
build and staging bash conditions to cover the new RID.
- `steps-test-js.yml` — added `linux-arm64` to `rid` values; expanded
all Linux/macOS bash conditions to cover the new RID.
- `steps-pack-js.yml` — added `linux-arm64` to the assembly sources
array; updated header comment.
- `sdk_v2/js/script/install-native.cjs` — strengthened the missing-RID
case from a silent `console.warn + return` to a thrown Error with a
clear message directing users to `FOUNDRY_LOCAL_SKIP_INSTALL=1`.

**Unchanged (intentional):**
- `sdk_v2/js/script/copy-native.mjs` and `pack-prebuilds.mjs` — local-dev
Expand All @@ -191,10 +217,11 @@ shape.
stamped via `npm version` in `js_pack`.
- **Signing:** Authenticode for Windows, ESRP MacAppDeveloperSign for
macOS, none for Linux, none for the `.tgz`.
- **Single combined tarball:** `js_pack` assembles all four prebuilds
- **Single combined tarball:** `js_pack` assembles all five prebuilds
into one `foundry-local-sdk-<version>.tgz`.
- **JS scoped out of WinML.**
- **Linux ARM64 deferred** to the cross-cutting ARM64 work item.
- **Linux ARM64 ORT package:** `Microsoft.ML.OnnxRuntime.Foundry` (CPU-only),
matching the C++ native ARM64 pipeline.

## Open items

Expand Down
38 changes: 23 additions & 15 deletions .pipelines/v2/sdk_v2-pipeline-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ In scope: `sdk_v2/cpp` (native runtime), `sdk_v2/cs/src` (C# SDK),
for both C# (via NuGet) and Python (bundled in the wheel), replacing the
legacy `foundry-local-core` from neutron-server.

Out of scope: JS, Rust, and a standalone `foundry-local-runtime` Python wheel.
JS is documented separately in `sdk_v2-js-pipeline-plan.md`. Rust and a standalone
`foundry-local-runtime` Python wheel remain out of scope.

## Top-level pipelines

Expand All @@ -31,6 +32,7 @@ are gated separately via `.pipelines/v1/templates/stages-sdk-v1.yml`.
| Windows x64 | `onnxruntime-Win-CPU-2022` | ✅ | ✅ | Also stages public headers |
| Windows ARM64 | `onnxruntime-Win-CPU-2022` | ✅ | ❌ | Cross-compiled from x64 host |
| Linux x64 | `onnxruntime-Ubuntu2404-AMD-CPU` | ✅ | ✅ | Pulls extra `OnnxRuntime.Gpu.Linux` pkg |
| Linux ARM64 | `onnxruntime-linux-ARM64-CPU-2019`| ✅ | ✅ | Native CPU-only build |
| macOS ARM64 | `AcesShared` (Sequoia) | ✅ | ✅ | Native |

## Architectural decisions (locked)
Expand Down Expand Up @@ -86,7 +88,8 @@ are gated separately via `.pipelines/v1/templates/stages-sdk-v1.yml`.
for the wheel install path:
- `onnxruntime-core` (Windows/macOS)
- `onnxruntime-genai-core` (Windows/macOS)
- `onnxruntime-gpu` / `onnxruntime-genai-cuda` (Linux)
- `onnxruntime-gpu` / `onnxruntime-genai-cuda` (Linux x64)
- `onnxruntime` / `onnxruntime-genai` (Linux ARM64, CPU-only)

Import-name mapping is platform-dependent: Linux uses `onnxruntime` /
`onnxruntime_genai`; Windows/macOS use `onnxruntime_core` /
Expand Down Expand Up @@ -136,10 +139,11 @@ are gated separately via `.pipelines/v1/templates/stages-sdk-v1.yml`.
```
.pipelines/v2/
└── templates/
├── stages-sdk-v2.yml # Coordinator: native + cs + python
├── stages-build-native.yml # 4 build stages + 1 pack stage (C++)
├── stages-sdk-v2.yml # Coordinator: native + C# + Python + JS
├── stages-build-native.yml # 5 native build stages + C++/NuGet pack stages
├── stages-cs.yml # C# build + test
├── stages-python.yml # Python build + test
├── stages-js.yml # JS build + test + combined npm pack
├── steps-prefetch-nuget.yml # ORT/GenAI/WinML NuGet pre-fetch (pwsh + bash)
├── steps-build-windows.yml # arch: x64 | arm64 (always bundles WinML)
├── steps-build-linux.yml
Expand All @@ -162,14 +166,17 @@ compute_version
|
|-- cpp_build_win_x64 ----------+
|-- cpp_build_win_arm64 --------|
|-- cpp_build_linux_x64 --------+--> pack_nuget --+--> cs_build --+--> cs_test_win_x64
|-- cpp_build_osx_arm64 --------+ | |--> cs_test_linux_x64
| | +--> cs_test_osx_arm64
| +--> (cs-sdk-v2 artifact)
|-- cpp_build_linux_x64 --------|
|-- cpp_build_linux_arm64 ------+--> pack_nuget --> cs_build --+--> cs_test_win_x64
|-- cpp_build_osx_arm64 --------+ |--> cs_test_linux_x64
| |--> cs_test_linux_arm64
| +--> cs_test_osx_arm64
|
| +--> py_build_win_x64 --> py_test_win_x64
+-->|--> py_build_linux_x64 --> py_test_linux_x64
+--> py_build_osx_arm64 --> py_test_osx_arm64
|-- python_build_win_x64 ------> python_test_win_x64
|-- python_build_win_arm64 ----> (build-only)
|-- python_build_linux_x64 ----> python_test_linux_x64
|-- python_build_linux_arm64 --> python_test_linux_arm64
+-- python_build_osx_arm64 ----> python_test_osx_arm64
```

* All build stages are independent (`dependsOn: [compute_version]`) and run
Expand All @@ -178,7 +185,7 @@ compute_version
* The Windows native build always bundles the reg-free WinML 2.x runtime,
which links against the same `ortVersion` as every other platform — there
is no separate WinML-aligned ORT pin or build flavor.
* Tests run on `cpp_build_win_x64`, `cpp_build_linux_x64`, and
* Tests run on `cpp_build_win_x64`, both Linux native stages, and
`cpp_build_osx_arm64`. The ARM64 Windows stage cross-compiles from an x64
host and skips tests.

Expand All @@ -193,6 +200,7 @@ Published via 1ES `templateContext.outputs` (no manual `PublishPipelineArtifact`
| `cpp_build_win_x64` | `cpp-native-include` | Public headers (sourced once, from win-x64) |
| `cpp_build_win_arm64` | `cpp-native-win-arm64` | `foundry_local.dll`, `.pdb`, `.lib` + `Microsoft.Windows.AI.MachineLearning.dll` |
| `cpp_build_linux_x64` | `cpp-native-linux-x64` | `libfoundry_local.so` |
| `cpp_build_linux_arm64` | `cpp-native-linux-arm64` | `libfoundry_local.so` (CPU-only) |
| `cpp_build_osx_arm64` | `cpp-native-osx-arm64` | `libfoundry_local.dylib` |
| `cpp_pack_nuget` | `cpp-nuget` | `Microsoft.AI.Foundry.Local.Runtime.<version>.nupkg` (bundles WinML on Windows) |

Expand Down Expand Up @@ -276,6 +284,7 @@ Test data is fetched on every stage that runs tests:

* `cpp_build_win_x64`
* `cpp_build_linux_x64`
* `cpp_build_linux_arm64`
* `cpp_build_osx_arm64`
* All `cs_test_*` and `py_test_*` stages

Expand Down Expand Up @@ -309,15 +318,14 @@ Build output directories follow `build.py`'s convention:
* **ESRP signing of native binaries.** Slot a signing stage between the
builds and pack once the unsigned end-to-end is fully stable.
* **Publishing.** No push to NuGet/internal feeds from this pipeline.
* **Linux ARM64 / macOS x64.** Add when there's a customer ask; pools and
pack support are both ready.
* **macOS x64.** Add when there's a customer ask.
* **Code coverage upload.** `run_coverage.ps1` exists for local use but is
not wired into CI.

## Things explicitly out of scope

- No `foundry-local-runtime` standalone wheel.
- No JS or Rust sdk_v2 stages.
- No Rust sdk_v2 stages.
- No multi-repo `Foundry-Local`/`test-data-shared` path-juggling logic in
the sdk_v2 templates — sdk_v2 paths are repo-relative.
- No private Azure DevOps feed dependency for the Python wheel install
Expand Down
Loading
Loading