Skip to content

SPIKE-23: Foundry Local install artifacts, and the real mechanics of Azure Arc run command

Role: foundry-researcher (Opus). Status: research spike complete. Entirely read-only. No Azure resources created, no az command run, no spend, no software installed, no artifact downloaded, no model API called. First-party documentation review only. Date: 2026-07-30 Scope: resolve SPIKE-18 unknowns 3, 4 and 7, and go further into the two mechanisms track 2 of ADR-0011 actually depends on: the Foundry Local Windows install artifacts, and the Azure Arc run command's timeout, output, identity, and failure semantics. This spike deliberately runs before the install test, because SPIKE-18 recommendation 4 observed that resolving unknowns 3 and 4 may remove the need for blob staging entirely, and with it the only exception to ADR-0005 anywhere in track 2. Every factual claim is grounded in a first-party source, cited inline. Anything Microsoft has not published is marked UNKNOWN with the test or document that would resolve it. This spike authorizes no deployment and no spend. Depends on: docs/research/SPIKE-18-foundry-local-windows-server.md (the unknowns this closes), docs/adr/ADR-0013-foundry-local-windows-server-install.md (the decisions this tests), docs/adr/ADR-0011-multi-target-deployment-automation.md (the track), docs/adr/ADR-0005 (the governing identity ADR whose exception is in question).


Question

Seven questions. Questions 1 and 2 together decide whether the blob-staging path, and therefore the ADR-0005 exception in ADR-0013 decision 4, is necessary at all. That is the single most valuable output of this spike, and it is answered in the Verdict.

  1. What exactly does the direct installer at aka.ms/foundry-local-installer do? Is it an .exe, an .msi, a script, or a bootstrapper that fetches an MSIX? Is it machine-scope? Does it support a silent or unattended switch? (SPIKE-18 UNKNOWN #3. ADR-0013 decision 1 permits it only if both are confirmed.)
  2. Is there a stable, versioned, first-party URL for the FoundryLocal.msix package and its VcLibs.appx dependency, suitable for automation to fetch directly? (SPIKE-18 UNKNOWN #4.)
  3. What is the documented execution timeout for Arc run command? What are the output size limits? What happens when a script exceeds the timeout? (SPIKE-18 UNKNOWN #7.)
  4. Does Add-AppxProvisionedPackage -Online work under a non-interactive, SYSTEM-context run command, and what are the documented constraints?
  5. What are the documented failure modes and exit-code semantics of Arc run command, and how does Instance View report them?
  6. Is there a documented uninstall or teardown path for a machine-wide provisioned Foundry Local MSIX, and does removing the provisioned package clear the model cache?
  7. What Connected Machine agent version and resource-provider registrations are prerequisites, and are there newer requirements than ADR-0013 decision 3 recorded?

Findings

Q1. The "direct installer" is not an installer. It is a GitHub releases page serving the same MSIX

This is the finding that collapses ADR-0013 decision 1's conditional alternative.

aka.ms/foundry-local-installer is a 301 permanent redirect to https://github.com/microsoft/Foundry-Local/releases, resolved read-only this session. It is not a file. It is a release listing page in the first-party microsoft GitHub organization. The Foundry Local CLI reference describes it exactly that way and no more: "Alternatively, download the installer from the foundry-samples GitHub repository." Source: Foundry Local CLI reference. Note in passing that the link text says "foundry-samples" while the redirect target is microsoft/Foundry-Local, so even the doc's own description of the destination is stale.

The Windows assets published on that page are MSIX packages, not executables. The CLI preview release listing names them in this form:

  • foundry-0.10.1-win-x64-winml.msix (marked recommended)
  • foundry-0.10.1-win-x64.msix
  • foundry-0.10.1-win-arm64-winml.msix (marked recommended)
  • foundry-0.10.1-win-arm64.msix

with .pkg and .zip for macOS and .tar.gz for Linux. Source: microsoft/Foundry-Local releases, retrieved 2026-07-30.

So both halves of ADR-0013 decision 1's condition answer in the negative, and for the same reason:

  • Machine-scope: no, not by itself. There is no installer program with a scope option. The artifact is the MSIX, which is exactly the package winget is documented to refuse to install at machine scope: "winget install Microsoft.FoundryLocal --scope machine fails with 'The current system configuration doesn't support the installation of this package.' Cause: Winget blocks MSIX machine-scope installs." Source: Best practices and troubleshooting guide for Foundry Local. Machine-wide installation of that MSIX is achieved only by provisioning it, which is the Add-AppxProvisionedPackage -Online path ADR-0013 already selected.
  • Silent switch: not applicable. A raw .msix has no command-line switches. Silence is a property of the cmdlet that consumes it, and Add-AppxProvisionedPackage is a non-interactive PowerShell cmdlet by nature.

Two consequences that ADR-0013 does not currently carry:

  1. ADR-0013 decision 1's "permitted alternative if and only if machine-scope and silent" clause should be struck, not satisfied. There is no second mechanism to permit. The direct download and the winget path resolve to the same package; only the installation cmdlet differs. The decision becomes simpler, not more conditional.
  2. Variant selection matters, and the recommended variant is the wrong one for a GPU-less server. The -winml variants are marked recommended for general use, but Microsoft documents a silent failure mode for the WinML backend on GPU-less virtual machines: "The WinML backend requires a DirectX 12-capable GPU. Virtual machines without GPU passthrough return a successful response with empty content." Source: Get started with Foundry Local (Windows AI). A successful response with empty content is worse than an error for an automated validation step, because a naive check on "did the call return 200" passes. Track 2 targets a GPU-less host, so the non-winml variant is the correct artifact, and ADR-0013 decision 8's validation must assert on non-empty content, not merely on a successful call.

Q2. No first-party, stable, versioned artifact URL is documented, for either the MSIX or the dependency

Microsoft's own machine-wide install instruction is artifact-name-only and URL-free:

  1. Download the .msix and its dependency package.
  2. Run PowerShell as Administrator.
  3. Run the following command to install Foundry Local for all users:
powershell
Add-AppxProvisionedPackage -Online -PackagePath .\FoundryLocal.msix `
  -DependencyPackagePath .\VcLibs.appx -SkipLicense

Source: Best practices and troubleshooting guide for Foundry Local. It names FoundryLocal.msix and VcLibs.appx as if they were canonical filenames. Neither is. The real published Windows asset names are version- and architecture-embedded (foundry-0.10.1-win-x64.msix), and no page on Microsoft Learn states where VcLibs.appx comes from in this context.

Taking each artifact:

  • The Foundry Local MSIX. The only documented source is the aka.ms redirect to the GitHub releases listing. Because the asset filename embeds the version, a fixed-filename "latest" download URL cannot be formed from the documented material, and no such URL is documented. Separately, the release stream is not uniform: the release tagged v1.2.1 on that repository carries only source archives (v1.2.1.zip, v1.2.1.tar.gz) as assets, while the CLI preview releases carry the .msix files. Retrieved 2026-07-30 from microsoft/Foundry-Local releases. Automation therefore cannot assume "the latest release contains the MSIX."
  • The VCLibs desktop framework dependency. Microsoft Learn documents only two acquisition routes, and neither is a general-purpose automation URL. First, from the Windows SDK on a developer machine: the packages "can be found under %ProgramFiles(x86)%\Microsoft SDKs\Windows Kits\10\ExtensionSDKs\Microsoft.VCLibs.Desktop\14.0", included with Visual Studio when the UWP workload and the C++ Universal Windows Tools component are selected. Second, standalone download pages exist only for the legacy and unsupported v11.0 and v12.0 packages: "Older C++ Runtime framework packages for desktop applications, such as v11.0 and v12.0, are no longer supported. However, they can be downloaded and installed from these locations." For the current v14 package Microsoft states only that these packages "are distributed and updated through the Microsoft Store." Source: C++ Runtime packages for Desktop Bridge. A widely used aka.ms short link for the current desktop package circulates in Microsoft Q&A community answers, but it does not appear in first-party documentation prose, so this spike does not cite it as a documented URL. It is recorded as UNKNOWN #3 below.

But the decisive point for the blob question is not the URL, it is what scriptUri accepts. Microsoft's REST definition for the Arc run command script source states: "scriptUri: Specifies the script download location. It can be either SAS URI of an Azure storage blob with read access or public URI." Source: Machine Run Commands, Create Or Update (api-version 2026-07-15), and identically in the Azure CLI reference for --script-uri: az connectedmachine run-command.

That means:

  1. A public URI needs no SAS and therefore no secret. Azure Storage is one option for scriptUri, not a requirement.
  2. More simply still, the script payload can be delivered inline via source.script (the -SourceScript / --script form) and fetch the artifacts itself in-guest over HTTPS from a public location. Nothing about the artifacts has to transit an Azure blob at all. The run command's own documented examples use plain inline scripts. Source: Run command on Azure Arc-enabled servers (preview).

So the absence of a documented stable URL is a supply-chain and reproducibility problem, not an identity problem. It argues for pinning a known-good artifact copy, which is a deliberate operator choice, and not for a product-imposed SAS token.

Q3. There is no fixed timeout. The timeout is caller-specified, has no documented default, and a breach surfaces as TimedOut

SPIKE-18 UNKNOWN #7 asked whether Arc run command carries a hard execution timeout comparable to the Azure VM service. It does not, and the reason is now clear from the API surface.

The timeout is a property the caller sets. properties.timeoutInSeconds is an optional int32, "The timeout in seconds to execute the run command," on both the REST body and the CLI (--timeout-in-seconds). Microsoft's own examples use 3600. Sources: Machine Run Commands, Create Or Update, az connectedmachine run-command, Run command on Azure Arc-enabled servers (preview), REST API tab. No default value and no maximum are documented in either reference. That is UNKNOWN #4 below. Note that 3600 in the examples is an example value and must not be read as a default.

This is the "managed" shape, not the "action" shape, which is why the 90-minute figure does not apply. Microsoft states that Arc run command "is similar to the Run command functionality you can use on Azure VMs, including the restrictions outlined," so the Azure VM comparison table is the closest published guidance. That table separates two products: Action Run Command has a "90 min limit" for long running, allows "Only one active," and has "Large output: Limited to 4k (in status blob)"; Managed Run Command has a "Customer specified timeout," supports "Multiple in parallel or sequenced," and uploads large output "to customer append blob." Sources: Run command on Azure Arc-enabled servers (preview), Run scripts in a Windows or Linux VM in Azure with Run Command. Arc run command is a resource type (Microsoft.HybridCompute/machines/runCommands) with timeoutInSeconds, asyncExecution, and append-blob output, which is unambiguously the managed shape. The 90-minute Action Run Command limit that the operator's build-environment standards cite, and that ADR-0013 context force 7 carried as a caution, therefore does not transfer. A multi-GB model pull inside one invocation is not obviously blocked.

What happens on breach is documented, indirectly but unambiguously. The ExecutionState enumeration has exactly seven values: Unknown, Pending, Running, Failed, Succeeded, TimedOut, Canceled. Source: Machine Run Commands, Create Or Update. A timeout is therefore reported as a distinct terminal state, separable from Failed, and an automation caller can tell "the script broke" from "the script ran out of time." Whether the in-guest process is killed, and whether partial work is rolled back, is not documented and is UNKNOWN #5.

Output limits: 4 KB confirmed, and now with the mechanism named. "The output and error fields in instanceView are limited to the last 4 KB. To access the full output and error, you can forward the output and error data to storage append blobs by using -outputBlobUri and -errorBlobUri parameters while executing the Run command." Source: Run command on Azure Arc-enabled servers (preview), Azure CLI tab. Two extensions on SPIKE-18's record: it is the last 4 KB, not the first, so a compact result printed at the end of a noisy script survives while the noise is discarded; and on the managed shape the instance view "Reports progress and last 4k output during execution," meaning it is pollable mid-run and not only at completion. Source: Run Command overview.

One further control worth naming: asyncExecution. "Optional. If set to true, provisioning will complete as soon as script starts and will not wait for script to complete," default False. Source: Machine Run Commands, Create Or Update. For a long model pull, asyncExecution: true plus polling the instance view is the documented pattern that avoids tying up the deploying client, and it composes with a generous timeoutInSeconds.

A conflict worth recording, because it bears directly on the ADR-0005 exception. The Arc run command conceptual page states plainly: "Run command on Azure Arc-enabled servers doesn't currently support authenticating blobs by using managed identities." Yet the Microsoft.HybridCompute REST reference at api-version 2026-07-15 defines source.scriptUriManagedIdentity, properties.outputBlobManagedIdentity, and properties.errorBlobManagedIdentity, each with guidance to assign Storage Blob Data Reader for the script blob and Storage Blob Data Contributor for the append blobs, and the Azure CLI connectedmachine extension exposes all three as --script-uri-id, --output-blob-id, and --error-blob-id. Sources: Run command on Azure Arc-enabled servers (preview), Machine Run Commands, Create Or Update, az connectedmachine run-command. The parameters exist on the wire and in the tooling; the conceptual page says the feature does not work. This spike does not resolve which is right, and will not guess. It is UNKNOWN #6, and it matters because if the managed-identity properties function, even the opt-in log-capture path needs no SAS and ADR-0005 has no exception anywhere in track 2.

Q4. Provisioning under a SYSTEM-context run command is plausible, but the semantics are not what the ADR assumes

Nothing in Microsoft's documentation blocks Add-AppxProvisionedPackage -Online under a non-interactive machine context. Several documented properties, though, change what "installed" means and invalidate part of ADR-0013's stage-1 check.

The elevation and module requirements are satisfied. Microsoft's instruction is "Run PowerShell as Administrator." Source: Best practices and troubleshooting guide for Foundry Local. The run command's default machine context is elevated, and ADR-0013 decision 2's rejection of RunAsUser remains correct.

Server Core is out. This is a new, hard constraint. "You cannot install an app package (.appx) on an operating system that does not support Windows 8 apps. Apps are not supported on Server Core installations of Windows Server 2012, Windows Preinstallation Environment (Windows PE) 4.0, or on any versions of Windows older than Windows 8 and Windows Server 2012. To install and run apps on Windows Server 2016, you must install the Install Server with Desktop Experience." Source: Add-AppxProvisionedPackage (Dism), Windows Server 2025 reference. Azure Arc, by contrast, supports both: "For Windows Server, both Desktop and Server Core experiences are supported." Source: Connected Machine agent prerequisites. So a host can be perfectly Arc-manageable and still be unable to host Foundry Local. Track 2 must require Server with Desktop Experience, and the run command should check for it before acting. The cited editions in the DISM page are 2012 and 2016, so its applicability verbatim to Server Core 2025 is UNKNOWN #7, but the conservative reading is the only safe one.

Provisioning does not install for the account that ran it, and does not install for existing users until they log on. This is the most consequential finding of Q4. "Provisioned apps are staged in the image and are scheduled to be installed for every user of the Windows image at first logon or at the next logon, if the user account is already created." Source: Sideload Apps with DISM. The cmdlet reference frames the same thing as "adds an app package (.appx) that will install for each new user" and, for the -Online -FolderPath example, "The package will be installed for the current user and any new user account created on the computer." Source: Add-AppxProvisionedPackage (Dism).

Microsoft's own winget documentation corroborates the pattern for exactly this class of package: "WinGet will not be available until you have logged into Windows as a user for the first time, triggering Microsoft Store to register the Windows Package Manager as part of an asynchronous process." Source: Use WinGet to install and manage applications.

What this predicts for track 2, and it should be treated as a prediction to be tested rather than a fact: a run command that provisions the MSIX and then immediately runs foundry --version in the same SYSTEM session will very likely find no foundry on PATH, because no user has logged on since provisioning and no per-user registration has occurred. ADR-0013 decision 6 stage 1 uses exactly that pair of checks (Get-AppxPackage / provisioned-package list, and foundry --version) and would report a false failure. The correct stage-1 check for a provisioning install is Get-AppxProvisionedPackage -Online, which enumerates what is staged; Get-AppxPackage and foundry --version are checks of a different thing (per-user registration) and should be reported as a separate state, not folded into "installed."

This also raises a question the spike cannot answer from documentation and which the whole track hinges on: if the Foundry Local service is a per-user-registered MSIX app, does a headless server with no interactive logon ever run it at all? That is UNKNOWN #1 below and it is now the single highest-value question in track 2, ahead of throughput.

Microsoft advises against DISM provisioning on an already-deployed image with active users. "On a Windows image that has already been deployed, you should instead use the Add-AppxPackage cmdlet in PowerShell. If you do use the DISM app provisioning commands on a deployed Windows image with active users, you should log all users off of the image, so that you are the only user logged on, before you run the command." Source: Sideload Apps with DISM. Foundry Local's own troubleshooting page nonetheless prescribes the provisioning command on a running machine, so the two first-party pages are in tension. The operationally honest reading: provisioning a deployed server is Microsoft's own recommended Foundry Local workaround, but it is not the general-purpose recommendation, and a run command that does it should not be pointed at a host with interactive users on it.

Other documented constraints, each small and each real:

  • Dependency architecture must match. "If the package has dependencies that are architecture-specific, you must install the applicable architectures for the dependency on the target image. For example, you must install the x86 dependency on the x86 image." Source: Add-AppxProvisionedPackage (Dism). x64 VCLibs for an x64 server.
  • -SkipLicense needs nothing else, and its documented scope fits. "Adds an app package without a license file. Only use SkipLicense with apps that do not require a license on Enterprise or Server versions of the operating system. Using SkipLicense in other scenarios can compromise an image." Source: same page. A Windows Server target is within the sanctioned scope. There is no additional flag or prerequisite.
  • There is a cap of 24 provisioned apps per image. "You can only install 24 provisioned apps in an image." Source: Sideload Apps with DISM. Not a constraint for a single-purpose host, but it is a real ceiling to know about.
  • Sideloading policy may gate execution, not installation. "The computer does not have to be joined to a domain or have an activated sideloading product key before you install provisioned LOB apps. However, the apps will not run until the computer meets this sideloading requirement." Source: same page. That page dates from 2017 and predates current Windows policy defaults, and the Foundry Local MSIX is a Microsoft-published package rather than an unsigned line-of-business app, so whether any of this binds on Windows Server 2025 is UNKNOWN #8.
  • Reboot behaviour is not documented. The cmdlet reference for Add-AppxProvisionedPackage states no restart requirement, exposes no restart-suppression parameter, and its documented output type is Microsoft.Dism.Commands.ImageObject with no RestartNeeded member described. Source: Add-AppxProvisionedPackage (Dism). Absence of a documented reboot is not a documented absence of reboot. UNKNOWN #9. Pending-reboot interaction with online DISM servicing is likewise undocumented for this cmdlet.

Q5. Exit codes are honest, and SPIKE-18's finding is confirmed and extended

SPIKE-18 said the run command's success signalling is honest. Confirmed, and the reporting surface is richer than SPIKE-18 recorded.

MachineRunCommandInstanceView returns eight fields: startTime, endTime, executionState, executionMessage ("Communicate script configuration errors or execution messages"), exitCode ("Exit code returned from script execution"), output ("Script output stream"), error ("Script error stream"), and statuses[], each status carrying code, displayStatus, level (Info, Warning, or Error), message, and time. Source: Machine Run Commands, Create Or Update. The conceptual page adds the interpretation: "Instance View contains the execution state of the Run command (succeeded, failed, and so on), exit code, standard output, and standard error generated by executing the script. A nonzero exit code indicates an unsuccessful execution." and separates the two states cleanly: "InstanceViewExecutionState: Indicates whether your script was successful or not. ProvisioningState: Indicates whether the extension platform was able to trigger the Run command script or not." Source: Run command on Azure Arc-enabled servers (preview).

The important qualification, which the ADR should state because it is the difference between an honest signal and a useless one: the platform faithfully reports what the script returns. A PowerShell payload that catches its own errors, or that relies on a non-terminating error, exits 0 and will be reported as Succeeded. Honest plumbing does not make a dishonest script honest. ADR-0013 decision 6 rule 5 (fail-fast per stage, name the failing stage) and decision 8 (validate by service state and one inference call) are what actually earn the signal, and the payload must set $ErrorActionPreference and a deliberate exit code accordingly.

Documented failure modes, collected:

Failure modeSignalSource
Script ran and failedexecutionState: Failed, nonzero exitCode, error populatedrun-command
Script exceeded timeoutInSecondsexecutionState: TimedOutREST reference
Platform could not trigger the script at allprovisioningState reflects it; executionState may be Unknown or Pendingrun-command
Script configuration error (bad blob URI, unreachable scriptUri)executionMessageREST reference
Run command resource deleted mid-execution"If the script execution is still in progress, execution terminates."run-command
Mechanism blocked locally at the agentNever triggers; azcmagent config set extensions.blocklist "microsoft.cplat.core/runcommandhandlerwindows"run-command, Limit access
Agent older than 1.33Run command not present; it "is built in to the Connected Machine agent (starting with version 1.33)"run-command
asyncExecution: trueProvisioning succeeds when the script starts, so provisioning success is not execution successREST reference

Two limits recorded for completeness: on Linux, "Run command doesn't accept names longer than 36 characters" (not applicable to a Windows target), and the Azure VM managed run command has a documented cap of 25 run commands per machine. Sources: run-command, Run Command overview. Whether the 25 cap applies to Arc is not stated on the Arc page and is UNKNOWN #10, though the resources are deletable so it is a housekeeping matter rather than a design constraint.

Q6. Teardown is documented for the package and undocumented for the cache, and the two must be sequenced

Removing the provisioning is documented, and its limits are stated explicitly. Remove-AppxProvisionedPackage -Online -PackageName MyAppxPkg is the counterpart cmdlet. Microsoft is unusually direct about what it does not do: "When you remove a provisioned app, the app will not be installed for new user accounts. For the currently logged in user and other user accounts that are active on the computer, the app will not be removed from those accounts. The app will need to be uninstalled for those existing" accounts, via Remove-AppxPackage. Source: Sideload Apps with DISM. So a complete teardown on a multi-user host is two operations, not one: de-provision, then remove per user.

Foundry Local's own documented uninstall does not cover the provisioned case. The CLI reference gives one Windows uninstall command: winget uninstall Microsoft.FoundryLocal. Source: Foundry Local CLI reference. That is the inverse of the winget install, which is the per-user path the whole track rejected. It will not remove a provisioned package machine-wide. The uninstall documentation and the machine-wide install documentation are not symmetric, and an operator following the docs literally will leave a provisioned package behind.

Whether removal clears the model cache: UNKNOWN, and the safe assumption is that it does not. No Microsoft page states that uninstalling or de-provisioning Foundry Local deletes the downloaded models. What is documented is a separate, explicit cache surface: foundry cache location ("Shows the current cache directory"), foundry cache list ("Lists all models stored in the local cache"), foundry cache remove <model> ("Removes a model from the local cache"), and foundry cache cd <path> ("Changes the cache directory to the specified path"). Source: Foundry Local CLI reference. The existence of a user-relocatable cache directory is itself an argument that the cache is not package state: a cache moved with foundry cache cd to another drive plainly cannot be cleaned up by removing an MSIX. This is UNKNOWN #11.

The operational consequence is a sequencing rule, and it is not obvious: capture the cache location and clear the cache before removing the package, not after. foundry cache location and foundry cache remove require the CLI, and the CLI is gone once the package is removed. A teardown that de-provisions first strands a multi-gigabyte cache with no supported tool to enumerate it. On a disposable test VM this is moot because the VM is discarded, which is a further argument for ADR-0013 decision 11's disposable-VM choice.

Q7. The prerequisite list in ADR-0013 is incomplete, and one new platform caution applies to the test plan

Resource providers: ADR-0013 records one of five. Microsoft lists these as required to use Azure Arc-enabled servers:

ProviderRequired forIn ADR-0013?
Microsoft.HybridComputeArc-enabled servers themselves, and the machines/runCommands resource typeNo
Microsoft.GuestConfigurationMachine configuration / guest policyNo
Microsoft.HybridConnectivityArc SSH and connectivity endpointsYes
Microsoft.AzureArcDataOnly "if you plan to Arc-enable SQL Servers"Not applicable to track 2
Microsoft.Compute"for Azure Update Manager and automatic extension upgrades"No

Source: Connected Machine agent prerequisites. Microsoft.HybridCompute is the material omission: it is the namespace the run command resource lives in, and ADR-0013 decision 3 names only Microsoft.HybridConnectivity, which is the SSH fallback's prerequisite. Microsoft.Compute is worth registering for automatic extension upgrades, which matters given that the run command handler is an agent-delivered extension.

Agent version: 1.33 remains the documented floor, and no newer floor is published. "The Run command is built in to the Connected Machine agent (starting with version 1.33)." Source: Run command on Azure Arc-enabled servers (preview). ADR-0013 decision 3 is correct as written. A related version floor ADR-0013 does not record sits on the client side: the az connectedmachine run-command command group "is part of the connectedmachine extension for the Azure CLI (version 2.75.0 or higher)" and every subcommand is marked Preview. Source: az connectedmachine run-command.

Windows Server 2025 is explicitly supported by Arc, on x86-64 only, and "For Windows Server, both Desktop and Server Core experiences are supported." Note the collision with Q4: Arc supports Server Core, Appx provisioning does not. Also stated: "Azure Editions are supported on Azure Local." Source: Connected Machine agent prerequisites.

A user-right prerequisite ADR-0013 does not record. "The Azure Hybrid Instance Metadata Service runs under a low-privileged virtual account, NT SERVICE\himds. This account needs the 'log on as a service' right in Windows to run. In most cases, there's nothing you need to do, because this right is granted to virtual accounts by default. However, if your organization uses Group Policy to customize this setting, you'll need to add NT SERVICE\himds to the list of accounts allowed to log on as a service." Source: same page. This is the identity endpoint ADR-0013 decision 7 relies on for the in-guest system-assigned managed identity, so a hardened Group Policy environment can silently break decision 7.

Two platform cautions that bear on ADR-0013's test plan and target selection. First: "You shouldn't install Azure Arc on virtual machines hosted in Azure, Azure Stack Hub, or Azure Stack Edge, as they already have similar capabilities. You can use an Azure VM to simulate an on-premises environment for testing purposes only." Second: "Microsoft doesn't recommend running Azure Arc on short-lived (ephemeral) servers or virtual desktop infrastructure (VDI) VMs... Azure Arc doesn't know if the agent is offline due to planned system maintenance or because the VM was deleted, so it doesn't automatically clean up server resources that stopped sending heartbeats. As a result, you could encounter a conflict if you recreate a deleted VM with the same name and there's an existing Azure Arc resource with the same name." Source: same page. Neither blocks ADR-0013 decision 11, because that install test is explicitly scoped to require no Arc onboarding. They do constrain any later increment that Arc-onboards a disposable VM: the Arc machine resource must be deleted alongside the VM, or name collisions follow.


What is still UNKNOWN

#UnknownWhy it is not in the docsWhat resolves it
1Does a provisioned Foundry Local MSIX ever actually run on a headless server with no interactive logon? Provisioning schedules per-user installation "at first logon or at the next logon," and the Foundry Local service is part of the MSIX package.Microsoft documents MSIX provisioning semantics and Foundry Local separately, and never addresses the intersection. The product is positioned for end-user devices, so the no-logon case is outside its documented scope.The owner-gated install test, with one added step: after provisioning under a non-interactive elevated context, check Get-AppxProvisionedPackage -Online, then Get-AppxPackage -AllUsers, then attempt foundry service status without an interactive logon, then repeat after one interactive logon. This ranks ahead of throughput in value.
2Is there a stable, versioned, first-party URL for the Foundry Local Windows MSIX?The Learn instruction says only "download the .msix," and the only documented source is an aka.ms redirect to a GitHub releases listing whose asset names embed the version and whose latest tag does not always carry the MSIX.Ask Microsoft via the Foundry-Local issue tracker for a supported machine-wide acquisition URL, or accept an operator-pinned copy. Until then, automation must resolve the artifact at run time or use a pinned copy.
3Is there a first-party documented download URL for the current v14 Microsoft.VCLibs...Desktop framework package?Learn documents only the Windows SDK ExtensionSDKs path (developer machines) and standalone downloads for the unsupported v11 and v12 packages, and says the current package is "distributed and updated through the Microsoft Store." An aka.ms short link circulates in Microsoft Q&A community answers but not in first-party doc prose.Confirm whether the Foundry Local MSIX actually declares a VCLibs dependency at all by reading its AppxManifest.xml PackageDependency entries, before assuming the dependency is needed. If it is, request a documented URL, or take the package from a Windows SDK install.
4What are the default and maximum values of timeoutInSeconds for Arc run command?Neither the REST reference, the CLI reference, nor the conceptual page states a default or a ceiling. 3600 appears only as an example value.Read the response of a created run command that omitted the property and observe the value the service returns; and submit one deliberately large value and observe whether it is accepted or clamped. Both are cheap once an Arc host exists.
5On TimedOut, is the in-guest process killed, and what happens to partial work?Documented only as a terminal ExecutionState value. No behavioural description.A long-running no-op with a short timeoutInSeconds, then inspect whether the process persists on the host. Do this before any automation depends on a large model pull inside one invocation.
6Do the managed-identity blob parameters actually work for Arc run command? The conceptual page says managed-identity blob auth is unsupported; the 2026-07-15 REST API and the Azure CLI extension both expose scriptUriManagedIdentity, outputBlobManagedIdentity, and errorBlobManagedIdentity.A direct contradiction between a conceptual page and a generated API reference. Neither is annotated to explain the other.One test against an Arc-enabled host: create a run command with outputBlobManagedIdentity set to the system-assigned identity and no SAS, and see whether output lands in the blob. If it works, ADR-0013 decision 4's exception can be deleted outright rather than merely narrowed.
7Is Appx provisioning genuinely unavailable on Windows Server 2025 Server Core?The DISM cmdlet reference states the restriction for Server Core 2012 and requires Desktop Experience for Server 2016. It does not name 2025 either way, though the page is served under the Windows Server 2025 moniker.Treat Desktop Experience as required and have the run command assert it. A definitive answer needs either a Microsoft statement or a Server Core test, and neither is worth blocking on.
8Does any sideloading policy requirement gate execution of the Foundry Local MSIX on Windows Server 2025?The relevant guidance dates from 2017, predates current Windows policy defaults, and is written for unsigned line-of-business apps rather than Microsoft-published packages.The install test answers it incidentally: if the app runs, no gate applies. If it installs but will not run, check HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\Appx\AllowAllTrustedApps.
9Does Add-AppxProvisionedPackage -Online require or trigger a reboot, and how does it behave with a pending reboot?The cmdlet reference states no restart requirement, offers no restart parameter, and describes no RestartNeeded output member. Silence, not a guarantee.Observe during the install test: check pending-reboot state before and after, and whether the cmdlet returns any restart indication.
10Does the 25-run-command-per-machine cap apply to Arc, as it does to Azure VM managed run command?Documented on the Azure VM page; the Arc page says the two are "similar... including the restrictions outlined" but does not restate the number.Housekeeping rather than design: delete run command resources after use. Confirmable by creating resources until the service refuses, which is not worth doing.
11Does removing the Foundry Local package clear the model cache?No Microsoft page connects package removal to the cache. The cache is separately managed and user-relocatable via foundry cache cd, which argues it is not package state.Observe during the install test's teardown: record foundry cache location, de-provision, then check whether the directory still exists. Until answered, teardown must clear the cache first.

Unknowns 2, 3, 6 and 10 need no software install. Unknowns 1, 5, 7, 8, 9 and 11 all close from the same single owner-gated install test that ADR-0013 decision 11 already scopes, provided that test is extended with the logon-sequence check in unknown 1 and the teardown observation in unknown 11. Unknown 4 needs an Arc-enabled host and is therefore a later increment.

None of these unknowns is a blocker for authoring the automation. Unknown 1 is a potential blocker for the track, and it is the one to test first.


Recommendation

  1. Delete ADR-0013 decision 1's conditional alternative rather than satisfying it. There is no separate direct installer to permit. aka.ms/foundry-local-installer redirects to a GitHub releases listing serving the same MSIX that winget would install, with no scope option and no silent switch, because it is a package and not a program. Decision 1 should simply read: the artifact is the Foundry Local Windows MSIX plus any declared dependency, and the mechanism is Add-AppxProvisionedPackage -Online ... -SkipLicense.

  2. Pin the non-winml MSIX variant for GPU-less targets, and say why in the ADR. The -winml variants are marked recommended, and on a virtual machine without GPU passthrough the WinML backend "return[s] a successful response with empty content." An automated validation that checks only for a successful call will pass on a completely broken deployment. ADR-0013 decision 8 must assert on non-empty response content, and decision 9 should name the artifact variant explicitly rather than leaving it to whichever asset is marked recommended.

  3. Remove blob staging from the default path, and narrow the ADR-0005 exception to the opt-in log path only. scriptUri accepts "either SAS URI of an Azure storage blob with read access or public URI," and an inline source.script payload can fetch its own artifacts over HTTPS. Nothing about artifact delivery requires a blob or a SAS token. ADR-0013 decision 4's exception should be rewritten to apply solely to outputBlobUri and errorBlobUri when full log capture is deliberately enabled, and flagged as possibly removable entirely pending unknown 6.

  4. Test the managed-identity blob parameters before accepting the exception at all. The REST API at api-version 2026-07-15 and the Azure CLI extension both expose scriptUriManagedIdentity, outputBlobManagedIdentity, and errorBlobManagedIdentity, while the conceptual page says managed-identity blob authentication is unsupported. One test settles it. If the parameters work, track 2 has no exception to ADR-0005 anywhere, and the identity story becomes clean rather than caveated.

  5. Rewrite ADR-0013 decision 6 stage 1 to check the right thing. Get-AppxProvisionedPackage -Online is the idempotency check for a provisioning install. Get-AppxPackage and foundry --version check per-user registration, which provisioning schedules for the next logon and does not perform for the SYSTEM account that ran it. The stage must report two distinct states, "provisioned" and "registered for a user," and must not report a false failure when the first is true and the second is not.

  6. Extend the install test to answer unknown 1 first, before throughput. The question "does a provisioned MSIX service run on a host nobody logs into" outranks tokens per second, because a negative answer ends the track and a slow answer only constrains the model choice. Sequence: provision under a non-interactive elevated context, check Get-AppxProvisionedPackage -Online, attempt foundry service status with no interactive logon, then log on once and retry. The test costs nothing more than the test ADR-0013 decision 11 already authorizes, and the owner gate on installing software is unchanged.

  7. Add the missing prerequisites to ADR-0013 decision 3, and require Server with Desktop Experience. Register Microsoft.HybridCompute (the run command's own namespace, currently unrecorded), Microsoft.GuestConfiguration, and Microsoft.Compute alongside the Microsoft.HybridConnectivity already listed. Record the az connectedmachine extension floor of CLI 2.75.0. Record the NT SERVICE\himds "log on as a service" right, because ADR-0013 decision 7's managed identity depends on it. And add a hard target constraint: Server with Desktop Experience, because Arc supports Server Core and Appx provisioning does not.

  8. Strike the 90-minute timeout caution from ADR-0013 context force 7, and replace it with the managed-run-command reality. The 90-minute limit belongs to Azure VM Action Run Command. Arc run command is the managed shape: a customer-specified timeoutInSeconds, append-blob output, parallel execution, and an asyncExecution flag. A multi-GB model pull inside one invocation is not documented to be blocked. Set timeoutInSeconds explicitly rather than relying on an undocumented default (unknown 4), and consider asyncExecution: true with instance-view polling for the model-pull stage.

  9. Sequence teardown as clear-cache-then-de-provision, and record that the documented uninstall is asymmetric. winget uninstall Microsoft.FoundryLocal is the only uninstall Microsoft documents and it does not undo a provisioning install. The correct teardown is foundry cache location and foundry cache remove for each model first (the CLI disappears with the package), then Remove-AppxProvisionedPackage -Online, then Remove-AppxPackage for any user account that had already registered the app. ADR-0013 decision 6 rule 6 correctly keeps uninstall out of the install script; this belongs in a separate documented teardown procedure.

  10. Do not read ADR-0013's install test as needing Arc. Nothing in this spike changes that. The test provisions a package on a disposable Windows Server 2025 Desktop Experience VM and needs no Arc onboarding, no subscription, and no spend. If a later increment does Arc-onboard a disposable VM, delete the Arc machine resource with the VM, because Arc "doesn't automatically clean up server resources that stopped sending heartbeats" and a rebuilt VM with the same name will collide.

Verdict: blob staging is NOT required, and the ADR-0005 exception should be narrowed to an opt-in path that may itself be unnecessary

Stated plainly, because this is the output the tasking asked for.

The blob-staging path is avoidable, and questions 1 and 2 are what make it avoidable, though not in the way SPIKE-18 anticipated. SPIKE-18 recommendation 4 hoped a stable first-party artifact URL would exist and remove the need for staging. That hope is not realised: no stable, versioned, first-party URL is documented for either the Foundry Local MSIX or the current VCLibs desktop framework package, and Microsoft's own machine-wide install instruction names two filenames that do not match any published asset. The exception nonetheless falls away, for a better reason: the Arc run command never required a blob for artifact delivery in the first place. scriptUri accepts a public URI as well as a SAS URI, and an inline source.script payload can fetch its own artifacts over HTTPS from any reachable location. Azure Storage is one delivery option among several, not a product-imposed dependency, and the SAS token SPIKE-18 treated as unavoidable is avoidable by not using the feature that needs it.

Therefore ADR-0013 decision 4's exception to ADR-0005 is not required for the install path and should be rewritten. Its scope should narrow to outputBlobUri and errorBlobUri when an operator deliberately opts into full log capture beyond the 4 KB instance-view window. In default operation, track 2 has no SAS token, no protected parameter, and no secret surface of any kind, which is what ADR-0013 decision 5 already aimed at and can now claim without qualification.

And even that residual exception may be removable. The Microsoft.HybridCompute REST API at api-version 2026-07-15 and the Azure CLI connectedmachine extension both expose managed-identity properties for the script URI and for both output blobs, directly contradicting the conceptual page's statement that managed-identity blob authentication is unsupported. This spike does not resolve that contradiction and will not guess at it. One test against an Arc-enabled host settles it, and if the parameters function, track 2 carries no exception to ADR-0005 at all and the identity story needs no caveat.

What has not gone away is a supply-chain problem, and it should not be confused with an identity problem. Because no stable versioned first-party URL is documented, run-time resolution of the artifact from a redirect to a GitHub releases listing is a moving target: asset filenames embed versions, the latest tag does not always carry a Windows MSIX, and a winml variant marked recommended is the wrong artifact for a GPU-less host and fails silently rather than loudly. An operator who wants reproducibility, version pinning, and availability independent of an upstream release page has a perfectly good reason to keep a pinned copy of a known-good artifact in their own storage. That is a deliberate engineering choice with a cost the operator accepts, not a constraint the product imposes, and if it is made it should be recorded as such rather than as a forced exception to the identity ADR. The distinction matters, because a forced exception invites nobody to revisit it and a deliberate choice does.

One finding outranks all of this for track 2's viability, and it is new. Provisioning an MSIX schedules per-user installation "at first logon or at the next logon"; it does not install for the account that ran the provisioning command. Microsoft's own winget documentation confirms the same pattern for the same class of package. A headless server that nobody logs into may therefore never register the Foundry Local app at all, and the CLI and its service may simply not exist from the perspective of an automated caller. That is UNKNOWN #1, it is cheap to test, and it should be the first thing the owner-gated install test measures, ahead of throughput. A negative answer ends track 2 in favour of track 3. A positive answer leaves the track exactly where ADR-0013 put it, minus one identity exception.

Net: the two read-only unknowns ADR-0013 decision 11 put ahead of the install test are now closed. Blob staging is optional. The ADR-0005 exception is not needed for the default path and may not be needed at all. Three separate corrections to ADR-0013 fall out of this spike (the phantom direct installer, the wrong idempotency check in stage 1, and the inapplicable 90-minute timeout caution), and one new hard target constraint is added (Server with Desktop Experience, not Server Core).


Sources

All first-party. Microsoft Learn unless noted. Retrieved 2026-07-30. No file was downloaded and no command was run against any Azure resource or host.

Foundry Local:

Azure Arc run command:

  • Run command on Azure Arc-enabled servers (preview) (agent 1.33 floor, no inbound ports, the RBAC split, protected parameters, Instance View fields and interpretation, the 4 KB cap, SAS requirements and suggested 24-hour expiry, the managed-identity blob statement, RunAsUser and Secondary Logon, preview and no-portal status, the agent blocklist, deletion terminating in-flight execution, the Linux 36-character name limit, the similarity statement to Azure VM run command): https://learn.microsoft.com/azure/azure-arc/servers/run-command
  • Machine Run Commands, Create Or Update, REST API for Azure Hybrid Compute, api-version 2026-07-15 (timeoutInSeconds, asyncExecution and its False default, the full ExecutionState enumeration including TimedOut, the MachineRunCommandInstanceView field list, scriptUri accepting a public URI, and the scriptUriManagedIdentity / outputBlobManagedIdentity / errorBlobManagedIdentity definitions): https://learn.microsoft.com/rest/api/hybridcompute/machine-run-commands/create-or-update
  • az connectedmachine run-command (the CLI 2.75.0 extension floor, preview status, --timeout-in-seconds with no stated default, and the three managed-identity parameters): https://learn.microsoft.com/cli/azure/connectedmachine/run-command
  • Run scripts in a Windows or Linux VM in Azure with Run Command (the action-versus-managed comparison table: the 90-minute limit and single-active restriction belonging to Action Run Command, and customer-specified timeout, append-blob output, parallel execution, and progress reporting with last 4 KB belonging to Managed Run Command; and the 25-run-command cap): https://learn.microsoft.com/azure/virtual-machines/run-command-overview
  • Connected Machine agent prerequisites (the five resource providers, Windows Server 2025 support on x86-64, Desktop and Server Core both supported by Arc, the NT SERVICE\himds Log on as a service right, the required Azure roles, the caution against Arc on Azure-hosted VMs, and the caution against Arc on short-lived servers): https://learn.microsoft.com/azure/azure-arc/servers/prerequisites
  • SSH access to Azure Arc-enabled servers (the Microsoft.HybridConnectivity registration prerequisite for the fallback path): https://learn.microsoft.com/azure/azure-arc/servers/ssh-arc-overview

MSIX provisioning and dependencies:

No local host measurement was taken for this spike and none was needed. Every finding above is documentary. The aka.ms short link for the current VCLibs desktop package that circulates in Microsoft Q&A community answers is deliberately not cited as a source, because it does not appear in first-party documentation prose; it is recorded as UNKNOWN #3 instead.