Enable tab completion for commands, options, and values. See the Shell Completion guide for setup instructions.
# Quick setup for PowerShell (permanent — add to profile)
winapp complete --setup powershell >> $PROFILE
# Or try it in the current session only
winapp complete --setup powershell | Out-String | Invoke-ExpressionInitialize a directory with Windows SDK, Windows App SDK, and required assets for modern Windows development.
winapp init [base-directory] [options]Arguments:
base-directory- Base/root directory for the app/workspace (default: current directory)
Options:
--config-dir <path>- Directory to read/store configuration (default: current directory)--setup-sdks- SDK installation mode: 'stable' (default), 'preview', 'experimental', or 'none' (skip SDK installation)--ignore-config,--no-config- Don't use configuration file for version management--no-gitignore- Don't update .gitignore file--use-defaults,--no-prompt- Do not prompt, and use default of all prompts--config-only- Only handle configuration file operations, skip package installation--exe <path>- Path to the application executable. Requires--sparse. Generates an identity-only sparse manifest for the exe instead of a full package/SDK setup.--sparse- Generate a sparse identity manifest (appxmanifest.xml) for an existing desktop exe. Skips SDK/package installation. Use with--exe.--name <name>- Override the package name (sparse only; default: inferred from the exe)--publisher <CN>- Override the publisher CN (sparse only; default: inferred from the exe's company name)--output-dir <path>- Directory to write the sparse manifest andAssets/(sparse only; default: asparse/folder in the current directory)--force- Overwrite an existingappxmanifest.xmlin the target directory (sparse only). Without it, init fails instead of replacing an existing manifest/assets.--add-js-bindings(npm only) - Addwinapp.jsBindingsto package.json and generate JS/TypeScript bindings, without prompting (incompatible with--setup-sdks none)
What it does:
- Creates
winapp.yamlconfiguration file (only when SDK packages are managed; skipped with--setup-sdks none) - Downloads Windows SDK and Windows App SDK packages
- Generates C++/WinRT headers and binaries
- Creates Package.appxmanifest
- Sets up build tools and enables developer mode
- Updates .gitignore to exclude generated files
- Stores shareable files in the global cache directory
- Generates JS bindings for Windows App SDK APIs when enabled (npm only)
Automatic project detection:
When init is run without a directory argument, it performs a breadth-first search of the current directory tree to find compatible projects (up to 10). Supported project types:
- Tauri —
tauri.conf.jsonfound one level below the directory - Electron —
package.jsonwithelectronin dependencies or devDependencies - Flutter —
pubspec.yamlat project root - .NET —
.csprojat project root - Rust —
Cargo.tomlat project root - C++ —
CMakeLists.txtat project root
The search skips commonly ignored directories (node_modules, bin, obj, .git, etc.). When a compatible project is found, subdirectories below it are not searched.
- If a directory argument is provided (e.g.,
winapp init .orwinapp init path/to/project), the search is skipped andinitchecks only that directory for a compatible project - If
--use-defaults(or--no-prompt) is set without a directory argument,initskips the search and initializes the current directory non-interactively, warning first if no known project type is detected there (e.g.,winapp init --use-defaults) - In non-interactive environments (piped stdin, CI, redirected input),
initautomatically uses--use-defaultsbehavior and emits a warning:Non-interactive environment detected. Using default values. - If the current directory is a compatible project,
initproceeds immediately - If exactly one project is found elsewhere, you're prompted to confirm
- If multiple projects are found, you can select which one to initialize — the current directory is always available as a fallback option
- If no projects are found, you're warned and asked whether to proceed anyway
- If the search reaches the 10-project limit, a warning suggests providing a directory argument
Automatic .NET project flow:
When a .csproj file is found in the target directory, init uses a streamlined .NET-specific flow:
- Validates and updates the
TargetFrameworkto a Windows-compatible TFM (e.g.,net10.0-windows10.0.26100.0) - Adds
Microsoft.WindowsAppSDKandMicrosoft.Windows.SDK.BuildToolsas NuGetPackageReferenceentries directly in the.csproj - Generates
Package.appxmanifest, assets, and a development certificate - Does not create a
winapp.yamlor download C++ projections (usedotnet restorefor NuGet packages)
Sparse identity mode (--exe + --sparse):
Generates an identity-only sparse package manifest for an existing desktop executable — the first step of the sparse packaging workflow. Unlike the full init flow, this skips all SDK/package installation (sparse identity packages have no SDK dependencies) and only generates a manifest and placeholder assets.
- Infers the package name, publisher, description, and version from the exe via
FileVersionInfo(override with--name,--publisher, or interactively) - Writes
appxmanifest.xml(with the exe name substituted intoExecutable) plus anAssets/folder to asparse/folder in the current directory (or--output-dir) - Uses
--use-defaults/--no-promptto skip the interactive override prompts (CI-friendly) --exewithout--sparseis an error
Assets are external. The sparse
.msixis identity-only: the generatedAssets/are resolved from the app's install directory (the external content location) at runtime, not bundled into the.msix. Deploy them alongside your application.
Next steps after winapp init --exe <exe> --sparse: winapp pack <appxmanifest.xml> to build the identity .msix, then winapp embed-identity <exe>. See the Sparse Packaging Guide for the full walkthrough.
Examples:
# Initialize current directory
winapp init
# Initialize with experimental packages
winapp init --setup-sdks experimental
# Initialize specific directory without prompts
winapp init ./my-project --use-defaults
# Initialize a .NET project (auto-detected from .csproj)
cd my-dotnet-app
winapp init
# Generate a sparse identity manifest for an existing exe (no SDK install)
winapp init --exe ./bin/Release/net8.0-windows/MyApp.exe --sparse --use-defaultsTip: Install SDKs after initial setup
If you ran init with --setup-sdks none (or skipped SDK installation) and later need the SDKs:
# Re-run init to install SDKs - preserves existing files (manifest, etc.)
winapp init . --use-defaults --setup-sdks stableUse --setup-sdks preview or --setup-sdks experimental for preview/experimental SDK versions.
Create a new WinUI app from an official Windows App SDK dotnet new template. Interactive by default; automatically uses defaults in non-interactive environments.
winapp new [options]Options:
-t, --template <short-name>- Template short name (e.g.winui,winui-navview,winui-mvvm,winui-lib,winui-unittest). Validated against the installed pack at run time; runwinapp new --listto see all. Default:winui(blank app).-n, --name <name>- Name for the new app/project (default: derived from--output, elseWinUIApp)-o, --output <path>- Directory to create the app in (default:./<name>)--use-defaults,--no-prompt- Do not prompt; use defaults (blank template, name from--output/--name, and keep the installed template pack rather than updating it)--force- Scaffold even if the output directory already contains files--template-version <latest|installed|version>- WinUI template pack version:latestinstalls the newest published pack,installedkeeps whatever is already downloaded (no network), or pin an explicit version such as1.2.3. Default: install the latest when no pack is present, otherwise prompt to update a stale pack (kept as-is under--use-defaults).--list- List the available WinUI templates and exit (installs the latest pack first if none is installed)--json- Format output as JSON
Templates:
The template list is read live from the installed pack, so it always reflects the version you have — run winapp new --list to see the current set. Common templates:
| Short name | Description |
|---|---|
winui |
Minimal blank WinUI 3 app (MSIX packaging) |
winui-navview |
NavigationView starter app |
winui-tabview |
TabView starter app |
winui-mvvm |
MVVM app (CommunityToolkit.Mvvm) |
winui-lib |
WinUI 3 class library |
winui-unittest |
Packaged MSTest app; tests run when it's launched |
Each template's canonical short name is the first alias dotnet new lists for it; any listed alias (e.g. winui3, wasdk-single) is also accepted. When run inside an existing WinUI project, dotnet new also surfaces item templates (e.g. a blank page), which winapp new adds into the current project rather than creating a new one.
Template pack versioning:
winapp new no longer pins a specific template pack version. If no pack is installed it installs the latest. If an older pack is already installed it checks the feed and, when a newer one exists, prompts whether to update — except in non-interactive/--use-defaults runs, which keep the installed pack. Use --template-version latest to always take the newest without prompting, or --template-version installed to always use the downloaded pack without a network check. Passing an explicit version (e.g. --template-version 1.2.3) always installs exactly that version — reinstalling even when a newer pack is already present — so scaffolding is reproducible across machines.
What it does:
- Verifies the .NET SDK is installed (fails fast with guidance if missing —
winappdoes not install toolchains) - Installs or updates the official WinUI template pack (
Microsoft.WindowsAppSDK.WinUI.CSharp.Templates) on demand - Enumerates the available templates from the installed pack and delegates scaffolding to
dotnet new <short-name>
WinUI app templates already include Windows packaging and identity (Package.appxmanifest), so no separate winapp init step is required. For app templates, use winapp run to build and launch the app. The winui-lib template produces a class library to reference from an app project (it has no app manifest). The winui-unittest template is a packaged MSTest app whose tests run when the app is launched (winapp run) — not via dotnet test. winapp new scaffolds against your installed .NET SDK's target framework and prints the appropriate next step for the template you choose.
Pass the global --verbose (-v) flag to echo every underlying dotnet invocation (pack query, update check, install, dotnet new list, scaffold) along with its full output — useful for diagnosing template-pack or scaffolding issues.
Examples:
# Interactive: pick a template, then a name (output defaults to ./<name>)
winapp new
# List the available templates without scaffolding
winapp new --list
# One-shot with a specific template
winapp new --name MyApp --template winui-navview
# Always use the newest template pack, no prompts
winapp new --name MyApp --template-version latest --use-defaults
# Show the underlying dotnet commands and their output
winapp new --name MyApp --verbose
# Non-interactive (agent) with machine-readable output
winapp new --use-defaults --name MyApp --jsonRestore packages and regenerate files based on existing winapp.yaml configuration.
winapp restore [options]Options:
--config-dir <path>- Directory containing winapp.yaml (default: current directory)
What it does:
- Reads existing
winapp.yamlconfiguration - Downloads/updates SDK packages to specified versions
- Regenerates C++/WinRT headers and binaries
- Stores shareable files in the global cache directory
Note
For .NET projects initialized with winapp init, there is no winapp.yaml. Use dotnet restore to restore NuGet packages instead.
Examples:
# Restore from winapp.yaml in current directory
winapp restoreUpdate packages to their latest versions and update the configuration file.
winapp update [options]Options:
--setup-sdks <stable|preview|experimental|none>- SDK installation mode:stable(default),preview,experimental, ornone(skip SDK installation)
What it does:
- Reads existing
winapp.yamlconfiguration in the current directory - Updates all packages to their latest available versions
- Updates the
winapp.yamlfile with new version numbers - Regenerates C++/WinRT headers and binaries
Examples:
# Update packages to latest versions
winapp update
# Update including experimental packages
winapp update --setup-sdks experimentalCreate MSIX packages from prepared application directories. Requires a manifest file (Package.appxmanifest preferred, appxmanifest.xml also supported) to be present in the target directory, in the current directory, or passed with the --manifest option. (run init or manifest generate to create a manifest)
Pass multiple input folders to create an .msixbundle for multi-architecture distribution (see Multi-architecture bundles below).
winapp pack <input-folder> [input-folder...] [options]Arguments:
input-folder- One or more directories containing the application files to package. Pass multiple folders (e.g.,./publish/x64 ./publish/arm64) to create an MSIX bundle. For sparse identity packages, pass a sparseappxmanifest.xmlfile directly instead of a folder (see Sparse identity packages below).
Options:
--output <filename>- Output file name. For single packages:<name>_<version>_<arch>.msix(falling back to<name>_<version>.msix,<name>_<arch>.msix, or<name>.msix). For bundles:<name>_<version>_<arch1>_<arch2>.msixbundle.--name <name>- Package name (default: from manifest)--manifest <path>- Path to manifest file (Package.appxmanifestpreferred,appxmanifest.xmlalso supported; default: auto-detect)--cert <path>- Path to signing certificate (enables auto-signing)--cert-password <password>- Certificate password (default: "password")--generate-cert- Generate a new development certificate--install-cert- Install certificate to machine--publisher <name>- Publisher for certificate generation. Accepts a full X.500 distinguished name or a bare name (automatically wrapped asCN=<name>)--self-contained- Bundle Windows App SDK runtime--skip-pri- Skip PRI file generation--executable <path>- Path to the executable relative to the input folder (also--exe). Used to resolve$targetnametoken$placeholders in the manifest.
What it does:
- Validates and processes Package.appxmanifest files
- Resolves
$placeholder$tokens in the manifest (see Manifest placeholders below) - Ensures proper framework dependencies
- Updates side-by-side manifests with registrations
- Automatically discovers and bundles any non-image files referenced in the manifest (e.g., AppExtension
manifest.json, config files) from the manifest directory or input folder if they are missing from staging - Automatically discovers third-party WinRT components and registers their activatable classes (see WinRT component discovery below)
- Handles self-contained WinAppSDK deployment
- Signs package if certificate provided
When the input is a sparse appxmanifest.xml file (one declaring <uap10:AllowExternalContent>true</uap10:AllowExternalContent> under <Properties>) rather than a folder, winapp pack builds an identity-only .msix — it packages just the manifest, with no application binaries or assets. This is step 2 of the sparse packaging workflow.
# Build a signed identity package from a sparse manifest
winapp pack ./sparse/appxmanifest.xml --cert ./devcert.pfx- Output defaults to
<PackageName>.identity.msixin the current directory (override with--output). - Signing happens only when
--cert(or--generate-cert) is provided. - If you instead pass a folder whose manifest declares
AllowExternalContent, the existing folder-packaging behavior applies, butwinapp packwarns if it finds assets (.png/.jpg/.ico) or binaries (.exe/.dll/.so) — for sparse packages these belong at the external location, not inside the.msix.
After packing, run winapp embed-identity <exe> and register the package in your installer with Add-AppxPackage -Path <msix> -ExternalLocation <install-dir>. See the Sparse Packaging Guide.
When packaging, winapp pack automatically scans NuGet packages defined in the winapp.yaml or *.csproj for third-party WinRT components (e.g., Win2D). It parses .winmd files to extract activatable class names and locates their implementation DLLs. The discovered entries are registered as follows:
- Framework-dependent (default): Activatable classes are added as
<InProcessServer>entries in thePackage.appxmanifest - Self-contained (
--self-contained): Activatable classes are embedded in side-by-side (SxS) manifests within the executable
Placeholder resolution during packaging:
If the manifest contains $targetnametoken$ in the Executable attribute:
- If
--executableis provided (path relative to the input folder), the placeholder is replaced with the specified value - Otherwise,
winapp packscans the input folder root for.exefiles — if exactly one is found, it is used automatically - If zero or multiple
.exefiles are found, an error is shown asking you to specify--executable
Examples:
# Package directory with auto-detected manifest
winapp pack ./dist
# Package with custom output name and certificate
winapp pack ./dist --output MyApp.msix --cert ./cert.pfx
# Package with generated and installed certificate and self-contained WinAppSDK runtime
winapp pack ./dist --generate-cert --install-cert --self-contained
# Package with explicit executable (resolves $targetnametoken$ in manifest)
winapp pack ./dist --executable MyApp.exeWhen multiple input folders are passed, winapp pack creates an .msixbundle containing one .msix per architecture:
# Create unsigned bundle for Microsoft Store submission
winapp pack ./publish/x64 ./publish/arm64
# Create signed bundle for sideloading
winapp pack ./publish/x64 ./publish/arm64 --cert ./devcert.pfx
# Self-contained bundle
winapp pack ./publish/x64 ./publish/arm64 --self-contained --generate-certThe command auto-detects each folder's architecture from the primary executable's PE header, validates consistency across slices (Identity, Capabilities, Dependencies), and produces a <Name>_<Version>_<arch1>_<arch2>.msixbundle.
Manifest resolution for bundles:
Each slice in the bundle needs a manifest. The command resolves manifests in this order:
-
--manifest <path>— If specified, this single manifest is used for all slices. TheProcessorArchitectureis automatically updated per-slice to match the detected architecture. -
Per-folder manifest — If each input folder contains a
Package.appxmanifest(orappxmanifest.xml), that folder's manifest is used for its slice. -
Current directory fallback — If a folder has no manifest, the command looks for
Package.appxmanifestin the current working directory and uses it (with architecture auto-stamped).
In all cases, the manifest is automatically updated: placeholders are resolved, dependencies are injected, and the ProcessorArchitecture is force-set to the detected architecture. After resolution, a cross-slice validation ensures that Identity (Name, Version, Publisher), Capabilities, and Dependencies are consistent across all slices — only ProcessorArchitecture may differ.
The package version defined in the slices is atributed to the MSIX bundle version, except if it's 0.0.0.0, in which case a timestamp-based version is automatically generated.
# Option 1: Single shared manifest (simplest for most projects)
# Place Package.appxmanifest in your project root and run from there
winapp pack ./publish/x64 ./publish/arm64
# Option 2: Explicit manifest path
winapp pack ./publish/x64 ./publish/arm64 --manifest ./src/Package.appxmanifest
# Option 3: Per-folder manifests (useful if slices have different app extensions)
# Each folder already contains its own Package.appxmanifest
winapp pack ./publish/x64 ./publish/arm64Create app identity for debugging using sparse packaging. The exe stays in its original location — Windows associates identity with it via Add-AppxPackage -ExternalLocation.
When to use this vs
winapp run: Usecreate-debug-identitywhen the exe is separate from your app code (e.g., Electron apps whereelectron.exeis innode_modules), or when specifically testing sparse package behavior. For most frameworks where the exe is in your build output folder, usewinapp runinstead — it registers a full loose layout package and launches the app. See the Debugging Guide for a full comparison.
winapp create-debug-identity [entrypoint] [options]Arguments:
entrypoint- Path to executable (.exe) or script that needs identity
Options:
--manifest <path>- Path to the app manifest file, eitherPackage.appxmanifestorappxmanifest.xml(default: auto-detectPackage.appxmanifestorappxmanifest.xmlin the current directory)--no-install- Don't install the package after creation--keep-identity- Keep the manifest identity as-is, without appending.debugto the package name and application ID
What it does:
- Modifies executable's side-by-side manifest
- Registers sparse package for identity
- Enables debugging of identity-requiring APIs
Examples:
# Add identity to executable using local manifest
winapp create-debug-identity ./bin/MyApp.exe
# Add identity with custom manifest location
winapp create-debug-identity ./dist/app.exe --manifest ./custom-manifest.xml
# Create identity for hosted app script
winapp create-debug-identity app.pyConnect a desktop application to its sparse identity package by embedding the <msix> element into the app's side-by-side (fusion) manifest. This is step 3 of the sparse packaging workflow — it tells Windows which identity package the running exe belongs to.
winapp embed-identity <target> [options]Arguments:
target- The file to update. Auto-detected by extension:.exe(EXE mode) — embeds the<msix>element directly into the exe's side-by-side manifest usingmt.exe..xml/.manifest(XML mode) — inserts or replaces the<msix>element in an external SxS manifest file (created if it doesn't exist). Rebuild your app afterward so the updated manifest is embedded in the binary.
Options:
--manifest <path>- Path to the sparseappxmanifest.xmlto read identity (packageName, publisher, applicationId) from. When omitted, the command searches asparse/folder beside the target first, then in the current directory, then the target's directory and the current directory, forappxmanifest.xml.
Examples:
# EXE mode — embed identity straight into the built exe
winapp embed-identity ./bin/Release/net8.0-windows/MyApp.exe
# XML mode — update a checked-in side-by-side manifest, then rebuild
winapp embed-identity ./app.manifest --manifest ./appxmanifest.xmlThis command is idempotent: re-running it replaces any existing
<msix>element rather than duplicating it.
Generate and manage Package.appxmanifest files.
Generate Package.appxmanifest from templates.
winapp manifest generate [directory] [options]Arguments:
directory- Directory to generate manifest in (default: current directory)
Options:
--package-name <name>- Package name (default: folder name)--publisher-name <name>- Publisher distinguished name (default: CN=<current user>). Accepts any valid X.500 DN; bare names are auto-wrapped as CN=<name>.--version <version>- Version (default: "1.0.0.0")--description <text>- Description (default: "My Application")--entrypoint <path>- Entry point executable or script--template <type>- Template type:packaged(default) orsparse--logo-path <path>- Path to logo image file--if-exists <Error|Overwrite|Skip>- Behavior when the manifest file already exists at the target path (default:Error)
Templates:
packaged- Standard packaged app manifestsparse- App manifest using sparse/external location packaging
Generated manifests use $placeholder$ tokens (dollar-sign delimited) that are resolved automatically at packaging time:
| Placeholder | Resolved to | Example |
|---|---|---|
$targetnametoken$ |
Executable name without extension | Executable="$targetnametoken$.exe" → Executable="MyApp.exe" |
$targetentrypoint$ |
Windows.FullTrustApplication |
Always resolved automatically |
This follows the same convention used by Visual Studio project templates, so manifests are portable across tooling.
How placeholders are resolved:
winapp pack— During packaging,$targetnametoken$is resolved using the--executableoption or by auto-detecting the single.exein the input folder. If multiple (or zero).exefiles are found and--executableis not specified, an error is shown.winapp create-debug-identity— When an entrypoint argument is provided,$targetnametoken$is resolved from it. Without an entrypoint, the executable placeholder must already be resolved in the manifest.winapp manifest generate --executable— When--executableis provided, manifest metadata (version, description) and icons are extracted from the executable, but the generated manifest still uses$targetnametoken$.exe; this placeholder is resolved later (e.g.winapp packorwinapp create-debug-identity).
PS: Keeping
$targetnametoken$in your checked-in manifest avoids hard-coding executable names and works with bothwinapp packand Visual Studio builds.
Examples:
# Generate standard manifest interactively
winapp manifest generate
# Generate with all options specified
winapp manifest generate ./src --package-name MyApp --publisher-name "CN=My Company" --if-exists overwriteAdd an execution alias (uap5:AppExecutionAlias) to a Package.appxmanifest. This allows launching the packaged app from the command line by typing the alias name.
winapp manifest add-alias [options]Options:
--name <alias>- Alias name (e.g.myapp.exe). Default: inferred from theExecutableattribute in the manifest.--manifest <path>- Path to Package.appxmanifest (default: search current directory)--app-id <id>- Application Id to add the alias to (default: first Application element)
What it does:
- Reads the manifest and infers the alias from the
Executableattribute (preserving placeholders like$targetnametoken$.exe) - Adds the
uap5namespace declaration if not already present - Adds an
<Extensions>block with<uap5:AppExecutionAlias>inside the target Application element - If the alias already exists, reports it and exits successfully
Examples:
# Add alias inferred from Executable attribute (e.g. $targetnametoken$.exe)
winapp manifest add-alias
# Add alias with explicit name
winapp manifest add-alias --name myapp.exe
# Add alias to specific manifest
winapp manifest add-alias --manifest ./dist/Package.appxmanifestGenerate all required MSIX image assets from a single source image.
winapp manifest update-assets <image-path> [options]Arguments:
image-path- Path to source image file (PNG, JPG, SVG, ICO, GIF, BMP, etc.)
Options:
--manifest <path>- Path to Package.appxmanifest file (default: search current directory)--light-image <path>- Path to a separate source image for light theme variants
Description:
Takes a single source image and generates a comprehensive set of MSIX image assets based on the manifest's asset references:
For each asset referenced in the manifest:
- 5 scale variants — base (no suffix),
.scale-125,.scale-150,.scale-200,.scale-400
For the app icon (Square44x44Logo / AppList, 44×44 base):
- 14 plated targetsize variants —
.targetsize-{16,20,24,30,32,36,40,48,60,64,72,80,96,256} - 14 unplated targetsize variants —
.targetsize-{size}_altform-unplated
Additionally:
- app.ico — Multi-resolution ICO file (16, 24, 32, 48, 256) for shell integration. If an existing
.icofile is found in the assets directory (e.g.AppIcon.icofrom a project template), it is replaced in-place rather than creating a duplicate
With --light-image:
- Light theme targetsize variants —
.targetsize-{size}_altform-lightunplated(app icon) - Light theme scale variants —
.scale-{factor}_altform-colorful_theme-light(tiles, store logo)
SVG support: SVG files are fully supported as source images. They are rendered as vectors directly at each target size, producing pixel-perfect results at all resolutions.
The command scales images proportionally while maintaining aspect ratio, centering them with transparent backgrounds when needed. Assets are saved to the Assets directory relative to the manifest location.
Examples:
# Generate assets with auto-detected manifest
winapp manifest update-assets mylogo.png
# Use an SVG source for best quality at all sizes
winapp manifest update-assets mylogo.svg
# Specify manifest location explicitly
winapp manifest update-assets mylogo.png --manifest ./dist/Package.appxmanifest
# Generate light theme variants from a separate image
winapp manifest update-assets mylogo.png --light-image mylogo-light.png
# Use the same image for both (generates all MRT light theme qualifiers)
winapp manifest update-assets mylogo.png --light-image mylogo.png
# With verbose output
winapp manifest update-assets mylogo.png --verboseCreate a loose layout package from a build output folder, register it with Windows using the Windows.Management.Deployment.PackageManager API, and launch the application — simulating a full MSIX install for debugging. Returns the process ID for debugger attachment.
winapp run operates in one of two modes, chosen automatically from the input:
- Folder mode — the input is a build-output folder (contains a
Package.appxmanifest/AppxManifest.xml). - Project mode — the input is a
.csproj, a.sln/.slnxsolution, or a directory containing one.winapp runbuilds the project and launches it, supporting both packaged and unpackaged WinUI apps. See Project mode below.
Tip
Mode selection is silent by default. If a directory was treated as a build-output folder when you
expected it to be built as a project, re-run with --verbose — folder mode reports why it was
chosen (No .csproj/.sln/.slnx with a runnable app found in '<path>' — running it as a build-output folder.). A directory is only built as a project when a .csproj/.sln/.slnx
with a runnable app sits at its top level; it is not searched recursively.
This is the preferred command for debugging with package identity for most frameworks (.NET, C++, Rust, Flutter, Tauri). Unlike
create-debug-identitywhich registers a sparse package for a single exe,winapp runregisters the entire folder as a loose layout package, just like a real MSIX install. See the Debugging Guide for common debugging workflows.
winapp run [<input>] [options]Arguments:
input- The app to run: a build-output folder (folder mode), a.csprojproject, a.sln/.slnxsolution, or a directory containing one of those at its top level (project mode; the directory is not searched recursively). Use.to build/run the project in the current directory. Optional — defaults to the current directory when omitted (matchesdotnet run).
Options:
--manifest <path>- Path to Package.appxmanifest (default: auto-detect from input folder or current directory)--output-appx-directory <path>- Output directory for the loose layout package (default:AppXinside the input folder directory)--args <string>- Command-line arguments to pass to the application. Alternatively, use--followed by arguments to avoid escaping (e.g.,winapp run . -- --flag value).--no-launch- Only create the debug identity and register the package without launching the application--with-alias- Launch the app using its execution alias instead of AUMID activation. The app runs in the current terminal with inherited stdin/stdout/stderr. Requires auap5:ExecutionAliasin the manifest (usewinapp manifest add-aliasto add one). Cannot be combined with--no-launch. Cannot be combined with--json.--debug-output- CaptureOutputDebugStringmessages and first-chance exceptions from the launched application. Framework noise (WinUI, COM, DirectX) is filtered from console output; the full log file captures everything. If the app crashes, automatically captures a minidump and analyzes it to show the exception type, message, and stack trace with source file:line numbers (resolved from PDBs in the build output folder). Managed (.NET) crashes are analyzed instantly with no external tools. Native (C++/WinRT) crashes show module names and offsets. When the crashed app is a WinUI 3 app (Microsoft.UI.Xaml.dllis loaded), an extra stowed-exception triage pass runs automatically to surface the originating HRESULT, its ErrorContext chain, and the full native XAML dispatch stack; the required debugger components are downloaded on first use (see Debugging, overridable via theWINAPP_DBGTOOLS_DIRenvironment variable). Only one debugger can attach to a process at a time, so other debuggers (Visual Studio, VS Code) cannot be used simultaneously. Use--no-launchinstead if you need to attach a different debugger. Cannot be combined with--no-launch. Cannot be combined with--json.--symbols- Download PDB symbols from Microsoft Symbol Server for richer native crash analysis with resolved function names. Only used with--debug-output. If omitted and a native crash occurs, the output will suggest adding this flag. This flag also improves the WinUI stowed-exception triage stack for WinUI 3 apps. First run downloads symbols and caches them locally; subsequent runs use the cache.--unregister-on-exit- Unregister the development package after the application exits. Only removes packages registered in development mode. Cannot be combined with--no-launch.--detach- Launch the application and return immediately without waiting for it to exit. Useful for CI/automation where you need to interact with the app after launch. Prints the PID to stdout (or in JSON with--json). Cannot be combined with--no-launch,--debug-output,--with-alias, or--unregister-on-exit.--clean- Remove the existing package's application data (LocalState, settings, etc.) before re-deploying. By default, application data is preserved across re-deployments.--json- Format output as JSON for programmatic consumption (e.g. CI/automation). Useful with--detachto capture the PID. Cannot be combined with--with-aliasor--debug-output.
Application data persistence:
By default, winapp run preserves your application's data (LocalState, RoamingState, Settings, etc.) when re-deploying. If your app writes data to ApplicationData.Current.LocalFolder or Environment.GetFolderPath(SpecialFolder.LocalApplicationData) within the package context, that data will survive across winapp run invocations.
Use --clean when you need a fresh start (e.g., to reset corrupted state or test first-run behavior).
What it does:
- Locates or generates the Package.appxmanifest
- Creates and registers a debug identity using a loose layout package
- Computes the Application User Model ID (AUMID)
- Launches the application using the registered identity (unless
--no-launchis specified) - Prints the process ID (PID) for debugger attachment
Examples:
# Register debug identity and launch app from build output
winapp run ./bin/Debug
# Launch with custom manifest and arguments
winapp run ./dist --manifest ./out/Package.appxmanifest --args "--my-flag value"
# Pass arguments after -- to avoid escaping (equivalent to --args)
winapp run ./bin/Debug -- --my-flag value
# Specify output directory for loose layout package
winapp run ./bin/Release --output-appx-directory ./AppXDebug
# Register identity without launching
winapp run ./bin/Debug --no-launch
# Launch via execution alias (console apps run in current terminal)
winapp run ./bin/Debug --with-alias
# Launch and capture OutputDebugString messages and crash diagnostics
winapp run ./bin/Debug --debug-output
# Download native symbols for richer crash analysis (C++/WinRT crashes)
winapp run ./bin/Debug --debug-output --symbols
# Combine with execution alias to debug console apps inline
winapp run ./bin/Debug --with-alias --debug-output
# Run and automatically clean up registration on exit
winapp run ./bin/Debug --with-alias --unregister-on-exit
# Launch and detach immediately (useful for CI/automation)
winapp run ./bin/Debug --detach
# Detach with JSON output (returns PID for scripting)
winapp run ./bin/Debug --detach --json
# Wipe application data (LocalState, settings) and start fresh
winapp run ./bin/Debug --cleanWhen the input is a .csproj, a .sln/.slnx solution, or a directory containing one (including .), winapp run builds the project with dotnet build and then launches it. It supports both packaged and unpackaged WinUI apps, and installs the matching-architecture Windows App Runtime the app needs before launching.
Solution input: point winapp run at a .sln/.slnx (or a directory containing one — a solution is preferred over loose .csproj files) and it resolves the runnable app project, then builds it with $(SolutionDir) and the sibling Solution* properties defined, so projects that depend on them build as they do in Visual Studio. Resolution rules:
- Test projects are skipped when auto-selecting, so a solution containing an app plus its tests resolves to the app with no
--projectneeded. (A WinUI test project is itself a packaged app, so output type alone can't distinguish it.) - If the only runnable project is a test project, it runs.
- If more than one runnable app project exists,
winapp rundoes not guess a startup project — it errors listing the candidates. Use--project <name>to choose, which is always honored, including to select a test project.
Packaged vs. unpackaged is detected automatically from the project's effective WindowsPackageType MSBuild property (never from manifest presence):
- Packaged (
WindowsPackageType=MSIX, the WinUI packaged default) — builds, then registers the build output as a loose-layout package and launches via AUMID (the same pipeline as folder mode). - Unpackaged (
WindowsPackageType=None) — builds, ensures the framework-dependent Windows App Runtime is installed, then launches the built.exedirectly. Force this for a packaged project with-p WindowsPackageType=None.
Project mode requires the .NET SDK 8.0.100 or newer (for MSBuild --getProperty).
Project-mode options (ignored in folder mode):
-c, --configuration <name>- Build configuration. Default:Debug.--arch <x64|arm64|x86>- Target architecture. Default: the current process architecture. Determines both the build RID and the architecture of the Windows App Runtime that gets installed.-r, --runtime <rid>- Target .NET runtime identifier (e.g.win-x64). Project mode uses only the RID's architecture, always builds the canonicalwin-<arch>, and rejects non-Windows RIDs (e.g.linux-x64). Its architecture overrides--arch.-f, --framework <tfm>- Target framework moniker for multi-targeted projects (e.g.net10.0-windows10.0.26100.0).--project <name-or-path>- When the input is a solution (.sln/.slnx) or a directory with multiple runnable app projects, selects which project to launch (by project name or path).--no-build- Skip building and run the existing build output (still evaluates output properties).--no-restore- Skip restoring the project before building.-p, --property <Name=Value>- MSBuild property, forwarded to both the build and the property evaluation. Repeatable (e.g.-p WindowsPackageType=None).
Build output & verbosity: the project is built in two steps — a dotnet build whose output streams live to your console, followed by a fast property-evaluation pass. winapp prints the exact dotnet build … invocation before the output, and streams warnings even on a successful build. Verbosity:
| Flag | dotnet verbosity | Adds |
|---|---|---|
| (default) | minimal |
— |
--verbose |
minimal |
winapp's build decision traces |
--quiet |
quiet |
— |
Under --json or --quiet the invocation and build output go to stderr so stdout stays pure JSON / clean.
Option applicability: the identity/loose-layout options (--manifest, --output-appx-directory, --no-launch, --with-alias, --unregister-on-exit, --clean, --executable) apply to packaged apps only. They are rejected with a clear error for unpackaged apps (which have no MSIX package). Launch/debug options (--args/--, --detach, --debug-output, --symbols, --json) work in both.
Project-mode examples:
# Build and run the project in the current directory (input defaults to ".")
winapp run
# Run a specific project
winapp run ./src/MyApp/MyApp.csproj
# Build and run from a solution (resolves the runnable app project, defines $(SolutionDir))
winapp run ./MyApp.sln
# Pick a startup project when the solution has more than one runnable app
winapp run ./MyApp.sln --project MyApp
# Release build for arm64
winapp run . -c Release --arch arm64
# Force an unpackaged run of a packaged project
winapp run . -p WindowsPackageType=None
# Run the existing build output without rebuilding, and capture crash diagnostics
winapp run . --no-build --debug-output
# Show winapp's build decision traces (dotnet build stays at minimal verbosity)
winapp run . --verbose
# Launch and detach (prints PID), forwarding args to the app
winapp run . --detach -- --my-flag valueMSBuild properties (NuGet package):
When using the Microsoft.Windows.SDK.BuildTools.WinApp NuGet package, dotnet run automatically invokes winapp run. The following MSBuild properties can be set in your .csproj to control behavior:
| Property | Default | Description |
|---|---|---|
EnableWinAppRunSupport |
true |
Enable/disable the run support functionality |
WinAppLaunchArgs |
(empty) | Arguments to pass to the app on launch |
WinAppRunUseExecutionAlias |
false |
Launch via execution alias instead of AUMID activation |
WinAppRunNoLaunch |
false |
Only register identity without launching |
WinAppRunDebugOutput |
false |
Capture OutputDebugString messages and first-chance exceptions. Only one debugger can attach at a time (prevents VS/VS Code). Use WinAppRunNoLaunch instead to attach a different debugger. |
WinAppRunDetach |
false |
Return immediately after launching instead of waiting for the app to exit. Prints the PID. |
WinAppRunUnregisterOnExit |
false |
Unregister the development package after the app exits |
WinAppRunClean |
false |
Remove the existing package's application data (LocalState, settings) before re-deploying |
WinAppRunSymbols |
false |
Download symbols from the Microsoft Symbol Server for richer native crash analysis. Only has an effect with WinAppRunDebugOutput. |
WinAppRunExecutable |
(empty) | Executable path relative to the build-output folder. Use when the manifest contains $targetnametoken$ and the output folder has more than one .exe. |
WinAppRunArgs |
(empty) | Raw arguments appended to the winapp run command line, for options with no dedicated property (for example --verbose). Appended after every property above. |
Mutually exclusive settings. WinAppRunNoLaunch and WinAppRunDetach each describe a different
launch behavior, so they conflict with the other launch properties and with each other. Setting a
conflicting pair fails the run with --X and --Y cannot be used together:
| Property | Cannot be combined with |
|---|---|
WinAppRunNoLaunch |
WinAppRunDetach, WinAppRunUseExecutionAlias, WinAppRunDebugOutput, WinAppRunUnregisterOnExit |
WinAppRunDetach |
WinAppRunNoLaunch, WinAppRunUseExecutionAlias, WinAppRunDebugOutput, WinAppRunUnregisterOnExit |
WinAppRunUseExecutionAlias, WinAppRunDebugOutput, and WinAppRunUnregisterOnExit can be combined
with each other. WinAppRunClean, WinAppRunSymbols, WinAppRunExecutable, and WinAppLaunchArgs
have no restrictions. WinAppRunArgs adds no restriction of its own, but a switch passed through it
is checked like any other, so WinAppRunArgs="--detach" still conflicts with WinAppRunNoLaunch.
<PropertyGroup>
<WinAppRunUseExecutionAlias>true</WinAppRunUseExecutionAlias>
<WinAppRunDebugOutput>true</WinAppRunDebugOutput>
</PropertyGroup>Unregister a sideloaded development package. Only removes packages that were registered in development mode (e.g., via winapp run or create-debug-identity). Store-installed or MSIX-installed packages are never removed.
winapp unregister [options]Options:
--manifest <path>- Path to Package.appxmanifest (default: auto-detect from current directory)--force- Skip the install-location directory check and unregister even if the package was registered from a different project tree--json- Format output as JSON
What it does:
- Reads the package name from the manifest
- Searches for both
{name}and{name}.debugpackages (the debug variant is created bycreate-debug-identity) - Verifies each package was registered in development mode (
IsDevelopmentMode == true) - Verifies the package's install location is under the current directory tree (unless
--force) - Unregisters matching packages
Examples:
# Unregister from current directory (auto-detects manifest)
winapp unregister
# Unregister with explicit manifest
winapp unregister --manifest ./Package.appxmanifest
# Force unregister even if registered from a different project tree
winapp unregister --force
# JSON output for scripting
winapp unregister --jsonGenerate, inspect, and install development certificates.
Generate development certificates for package signing.
winapp cert generate [options]Options:
--manifest <Package.appxmanifest>- Extract publisher information from Package.appxmanifest--publisher <name>- Publisher for the certificate. Accepts a full X.500 distinguished name (e.g.,CN=Contoso, O=Contoso Ltd, C=US) or a bare name which is automatically wrapped asCN=<name>--output <path>- Output certificate file path (supports absolute and relative paths)--password <password>- Certificate password (default: "password")--valid-days <valid-days>- Number of days the certificate is valid (default: 365)--install- Install the certificate to the local machine store after generation--if-exists <Error|Overwrite|Skip>- Set behavior if the certificate file already exists (default: Error)--export-cer- Export a.cerfile (public key only) alongside the.pfx. Useful for distributing the public certificate separately for trust installation.--json- Format output as JSON for programmatic consumption. Errors are also returned as JSON ({"error": "..."}).
Display certificate details from a PFX file. Useful for verifying a certificate matches your manifest before signing.
winapp cert info <cert-path> [options]Arguments:
cert-path- Path to the certificate file (PFX)
Options:
--password <password>- Password for the PFX file (default: "password")--json- Format output as JSON
Install certificate to machine certificate store.
winapp cert install <cert-path> [options]Arguments:
cert-path- Path to certificate file to install
Examples:
# Generate certificate for specific publisher
winapp cert generate --publisher "CN=My Company" --output ./mycert.pfx
# Generate certificate and export public key .cer file
winapp cert generate --publisher "CN=My Company" --export-cer
# Generate certificate with JSON output (for scripting)
winapp cert generate --publisher "CN=My Company" --json
# View certificate details
winapp cert info ./mycert.pfx
# View certificate details as JSON
winapp cert info ./mycert.pfx --json
# Install certificate to machine
winapp cert install ./mycert.pfxSign MSIX packages and executables with certificates.
winapp sign <file-path> <cert-path> [options]Arguments:
file-path- Path to MSIX package or executable to signcert-path- Path to the signing certificate (.pfx)
Options:
--password <password>- Certificate password (default: "password")--timestamp <url>- RFC 3161 timestamp server URL
Examples:
# Sign MSIX package
winapp sign MyApp.msix ./mycert.pfx
# Sign executable with a non-default certificate password
winapp sign ./bin/MyApp.exe ./mycert.pfx --password mypasswordCode-sign a file (exe, MSIX, or MSIX bundle) using Azure Trusted Signing — a cloud-managed signing identity, so no private key (PFX) ever lives on the local machine.
winapp az-sign <file-path> [options]Arguments:
file-path- Path to the file to sign (exe, msix, or msixbundle)
Options:
--subscription,-s- Azure subscription ID to use. If not provided and multiple subscriptions exist, you will be prompted--resource-group,-r- Resource group to narrow down signing accounts--account- Signing account name. Must be used with--resource-group--profile,-p- Certificate profile name. Must be used with--account--metadata-file,-m- Path to an existingmetadata.json. Skips resource discovery and account/profile selection prompts and signs directly. A non-interactive Azure credential should already be available; the CLI can otherwise fall back to an interactive tenant prompt oraz login, but the npm programmatic API is always non-interactive and fails instead of prompting
Authentication:
az-sign uses Azure's standard credential chain (DefaultAzureCredential). For CI/CD, set AZURE_TENANT_ID, AZURE_CLIENT_ID, and AZURE_CLIENT_SECRET (or use GitHub Actions OIDC / managed identity). An existing Azure CLI session (az login, including the azure/login GitHub Action) is also honored in any environment. Only when no credentials are found and the session is interactive will az-sign launch az login for you.
Prerequisites:
- An Azure Code Signing account and a certificate profile (created in the Azure portal after identity validation), plus the Code Signing Certificate Profile Signer role assigned to your identity. For more guidance, visit Azure Artifact Signing quickstart docs.
- A machine-wide x64 .NET 8 (or later) runtime installed. The Azure signing client library is a managed assembly that
signtool.exeloads in a separate process; winapp's own self-contained runtime does not satisfy it. Install it from https://dotnet.microsoft.com/download if signing fails with a runtime-load error. - The Microsoft Visual C++ Redistributable (x64). The Azure signing client library depends on the VC++ runtime, and because winapp downloads the raw NuGet package rather than the official client-tools installer, this dependency is not installed automatically. A clean machine can load-fail even with .NET and SignTool present. Install the latest x64 redistributable from https://aka.ms/vs/17/release/vc_redist.x64.exe if signing fails with a
0xc000007b, "The application was unable to start correctly", or missing-DLL error from the dlib.
Least-privilege CI: Auto-discovery (listing subscriptions, resource groups, accounts, and profiles) needs read access at a parent scope. To avoid every collection-listing call, pass all four of
--subscription,--resource-group,--account, and--profile:az-signthen validates the account and profile with direct resource reads (a GET on each named resource) instead of enumerating the parent collection, so a principal scoped to just that account and profile is sufficient. Omitting any one of them re-introduces a listing call — for example, leaving out--subscriptionmakesaz-signlist the subscriptions your identity can access — which a narrowly-scoped principal may not be permitted to do. A principal scoped only to a single certificate profile can skip validation entirely by passing a pre-generated--metadata-file(which specifies the account endpoint and profile directly).
Examples:
# Interactive — discover/select subscription, account, and profile
winapp az-sign ./app.msix
# Fully specified — no prompting (ideal for CI/CD)
winapp az-sign ./app.msix --subscription <sub-id> --resource-group <rg> --account <account> --profile <profile>
# Reuse an existing metadata.json (skips resource discovery and selection; authentication may still prompt)
winapp az-sign ./app.msix --metadata-file ./metadata.jsonGenerate a CodeIntegrityExternal.cat catalog file containing hashes of executable files from specified directories. This catalog is used with the TrustedLaunch flag in MSIX sparse package manifests (AllowExternalContent) to allow execution of external files not included in the package itself.
This is similar to how signtool.exe creates AppxMetadata\CodeIntegrity.cat when signing an MSIX package, but generates an external catalog for use with sparse/external location packaging.
winapp create-external-catalog <input-folder> [options]Arguments:
input-folder- One or more directories containing executable files to process. Separate multiple directories with semicolons (e.g.,"dir1;dir2")
Options:
--recursive,-r- Include files from subdirectories--use-page-hashes- Include page hashes when generating the catalog (produces a larger catalog with per-page hash data)--compute-flat-hashes- Include flat file hashes when generating the catalog--if-exists <Error|Overwrite|Skip>- Behavior when the output file already exists (default:Error)--output,-o- Output catalog file path. If not specified,CodeIntegrityExternal.catis created in the current directory. If a directory is specified, the default filename is appended.
What it does:
- Scans specified directories for executable files (PE binaries with code sections)
- Generates a Catalog Definition File (CDF) with hashes of all found executables
- Uses Windows CryptoCAT APIs to produce the
.catcatalog file - Non-executable files (e.g.,
.txt,.dllwithout code sections) are automatically skipped
Examples:
# Generate catalog for all executables in a directory
winapp create-external-catalog ./bin
# Include files in subdirectories
winapp create-external-catalog ./bin --recursive
# Specify a custom output path
winapp create-external-catalog ./bin --output ./dist/CodeIntegrityExternal.cat
# Overwrite existing catalog
winapp create-external-catalog ./bin --if-exists Overwrite
# Skip generation if catalog already exists
winapp create-external-catalog ./bin --if-exists Skip
# Include page hashes (for stricter code integrity validation)
winapp create-external-catalog ./bin --use-page-hashes
# Process multiple directories
winapp create-external-catalog "./bin;./lib" --recursive
# Combine multiple options
winapp create-external-catalog ./bin --recursive --use-page-hashes --compute-flat-hashes --output ./dist/CodeIntegrityExternal.cat --if-exists OverwriteWhen to use:
Use this command when building a sparse MSIX package that uses TrustedLaunch to verify external executables. The typical workflow is:
winapp manifest generate --template sparse— Create a sparse manifest withAllowExternalContentwinapp create-external-catalog ./bin— Generate the code integrity catalog for your app's executableswinapp pack— Package the manifest, assets, and catalog into an MSIX
Access Windows SDK tools directly. Uses tools available in Microsoft.Windows.SDK.BuildTools
winapp tool <tool-name> [tool-arguments]Available tools:
makeappx- Create and manipulate app packagessigntool- Sign files and verify signaturesmt- Manifest tool for side-by-side assemblies- And other Windows SDK tools from Microsoft.Windows.SDK.BuildTools
Examples:
# Use signtool to verify signature
winapp tool signtool verify /pa MyApp.msixSignature verification
Build tools are downloaded from NuGet and then executed, so winapp checks each one for a valid Microsoft Authenticode signature immediately before running it. This applies to every command that shells out to an SDK tool, including tool, package, and sign. A tool that fails the check is not run:
'mt.exe' is not validly signed by Microsoft, so it was not run (C:\...\mt.exe).
A failure here means the file on disk is not what Microsoft published — most often a corrupt or partial download. Delete the package from the NuGet cache and run the command again so winapp re-downloads it.
Run a Microsoft Store Developer CLI command. This command will download the Microsoft Store Developer CLI if not already downloaded. Learn more about the Microsoft Store Developer CLI.
winapp store [args...]Arguments:
args...– Arguments to pass directly to themsstoreCLI. See MSStore CLI documentation for available commands and options.
What it does:
- Ensures the Microsoft Store Developer CLI (
msstore) is downloaded and available on your system. - Forwards all arguments to the
msstoreCLI. - Runs the command showing output directly in your terminal.
Examples:
# List all apps in your Microsoft Partner Center account
winapp store app list
# Publish a package to the Microsoft Store
winapp store publish ./myapp.msix --appId <your-app-id>Get paths to installed Windows SDK components.
winapp get-winapp-path [options]What it returns:
- Paths to
.winappworkspace directory - Package installation directories
- Generated header locations
Search WinUI controls and samples for a working code example. WinUI-only: the corpus is the WinUI 3 Gallery and the Windows Community Toolkit (plus a few curated core patterns) — it does not cover WPF, WinForms, or other UI frameworks. A third source, the microsoft-ui-reactor ReactorGallery, is opt-in: it is excluded from a normal search and only searched when you pass --source reactor (its C#-only declarative samples don't paste into a standard XAML app, so reach for it only when building a Reactor/MVU project).
winapp find-ui "<query>" [options]The corpus is fetched from GitHub on first use and cached per-user under <global .winapp>/cache/find-ui, so the first run requires network access. Subsequent runs are served from the local cache (refreshed at most every 7 days, or on demand with --refresh).
Options:
--id <id>- Fetch the code (Gallery/Toolkit return XAML and/or C#; Reactor is C#-only) plus prerequisite notes for one or more scenario ids from a prior search (e.g.gallery-tabview-1). Repeatable. Ids are case-insensitive —GALLERY-TABVIEW-1resolves the same asgallery-tabview-1.--list- List every discoverable control/sample id instead of searching (Gallery + Toolkit + core; the opt-in Reactor source is excluded).--source <gallery|toolkit|reactor|core>- Restrict search results to a single source. (Search only — not valid with--list/--id.) Reactor is opt-in — it is excluded from a normal search, so--source reactoris the only way to search it.--max <N>- Maximum number of matched controls to return (default: 3). Applies to search only; ignored with--list/--id.--refresh- Bypass the local cache and re-fetch the WinUI corpus from GitHub.--json- Emit structured JSON (agent-friendly). For search, each match carriessource,control,score,description, and ascenariosarray whose entries hold the per-scenarioidandheader; for--id, full code. Under--jsonevery failure — including argument/parser errors such as a non-integer--max— is emitted as a flat{"error": "..."}object on stdout with a non-zero exit code, so output stays machine-readable.
Workflow: search compactly to find the right control and its scenario ids, then fetch the full code for the best match with --id.
Examples:
# Find a control by intent (compact results with scenario ids)
winapp find-ui "tabbed layout"
# Restrict to the Windows Community Toolkit
winapp find-ui "settings card" --source toolkit
# Restrict to Reactor (opt-in; C#-only declarative WinUI — Reactor projects only)
winapp find-ui "flex layout" --source reactor
# Fetch the full XAML + C# for a specific scenario
winapp find-ui --id gallery-tabview-1
# Agent-friendly structured output
winapp find-ui "color picker" --json
# Browse everything, or force a corpus refresh
winapp find-ui --list
winapp find-ui "navigation view" --refresh(Available in NPM package only) Generate JS bindings for Windows App SDK APIs. The bindings are declared by a "winapp": { "jsBindings": {...} } namespace in package.json and written to .winapp/bindings/.
npx winapp node generate-bindings [options]Options:
--verbose,-v- Enable verbose per-file codegen output--quiet,-q- Suppress progress and informational output
What it does:
- Reads the
winapp.jsBindingsblock frompackage.jsonand thewinmds.lock.jsonwritten by the lastwinapp restore, then emits typed.js+.d.tsbindings into.winapp/bindings/ - Does not modify
package.json— it is a passive regenerator. Adding thewinapp.jsBindingsblock and the@microsoft/dynwinrtruntime dependency happens duringwinapp initwhen JS bindings are enabled; this command fails fast if the block is absent - Warns (but does not write) if
@microsoft/dynwinrtis missing from your dependencies — runnpm installafterinithas added it
Note
Bindings are npm-only — they require invocation via npx winapp (the @microsoft/winappcli npm package); the standalone winget CLI does not surface them. Run winapp init interactively and opt in, or use winapp init . --use-defaults --add-js-bindings, before using this command to regenerate bindings. If you edit winapp.yaml, run npx winapp restore to refresh Windows dependencies before regenerating.
Examples:
# Regenerate JS bindings in the current project
npx winapp node generate-bindings
# Regenerate after editing winapp.jsBindings, with verbose output
npx winapp node generate-bindings --verboseSee the JS bindings guide for the end-to-end workflow and the
winapp.jsBindingsconfiguration options.
(Available in NPM package only) Generate native C++ or C# addon templates with Windows SDK and Windows App SDK integration.
npx winapp node create-addon [options]Options:
--name <name>- Addon name (default: "nativeWindowsAddon")--template- Select type of addon. Options arecsorcpp(default:cpp)--verbose- Enable verbose output
What it does:
- Creates addon directory with template files
- Generates binding.gyp and addon.cc with Windows SDK examples
- Installs required npm dependencies (nan, node-addon-api, node-gyp)
- Adds build script to package.json
Examples:
# Generate addon with default name
npx winapp node create-addon
# Generate custom named addon
npx winapp node create-addon --name myWindowsAddon(Available in NPM package only) Add app identity to Electron development process by using sparse packaging. Requires a Package.appxmanifest (create one with winapp init or winapp manifest generate if you don't have one).
Important
There is a known issue with sparse packaging Electron applications which causes the app to crash on start or not render the web content. The issue has been fixed in Windows but it has not propagated to external Windows devices yet. If you are seeing this issue after calling add-electron-debug-identity, you can disable sandboxing in your Electron app for debug purposes with the --no-sandbox flag. This issue does not affect full MSIX packaging.
To undo the Electron debug identity, use winapp node clear-electron-debug-identity.
npx winapp node add-electron-debug-identity [options]Options:
| Option | Description |
|---|---|
--manifest <path> |
Path to custom Package.appxmanifest (default: Package.appxmanifest in current directory) |
--no-install |
Do not install or modify dependencies; only configure the Electron debug identity |
--keep-identity |
Keep the manifest identity as-is, without appending .debug to the package name and application ID |
--verbose |
Enable verbose output |
What it does:
- Registers debug identity for electron.exe process
- Enables testing identity-requiring APIs in Electron development
- Uses existing Package.appxmanifest for identity configuration
Examples:
# Add identity to Electron development process
npx winapp node add-electron-debug-identity
# Use a custom manifest file
npx winapp node add-electron-debug-identity --manifest ./custom/Package.appxmanifest(Available in NPM package only) Remove package identity from the Electron debug process by restoring the original electron.exe from backup.
npx winapp node clear-electron-debug-identity [options]Options:
| Option | Description |
|---|---|
--verbose |
Enable verbose output |
What it does:
- Restores electron.exe from the backup created by
add-electron-debug-identity - Removes the backup files after restoration
- Returns Electron to its original state without package identity
Examples:
# Remove identity from Electron development process
npx winapp node clear-electron-debug-identityAll commands support these global options:
--verbose,-v- Enable verbose output for detailed logging--quiet,-q- Suppress progress messages--help,-h- Show command help
Winapp creates a directory to cache files that can be shared between multiple projects.
By default, winapp creates a directory at $UserProfile/.winapp as the global cache directory.
To use a different location, set the WINAPP_CLI_CACHE_DIRECTORY environment variable.
In cmd:
REM Set a custom location for winapp's global cache
set WINAPP_CLI_CACHE_DIRECTORY=d:\temp\.winappIn PowerShell and pwsh:
# Set a custom location for winapp's global cache
$env:WINAPP_CLI_CACHE_DIRECTORY=d:\temp\.winappWinapp will create this directory automatically when you run commands like init or restore.
The winapp CLI periodically checks for new versions and displays a one-line notice when an update is available. This check runs in the background and adds no latency to commands.
Update checks are automatically disabled in CI environments (GitHub Actions, Azure Pipelines, etc.).
To manually disable update checks, set the WINAPP_CLI_UPDATE_CHECK environment variable to 0.
In cmd:
set WINAPP_CLI_UPDATE_CHECK=0In PowerShell and pwsh:
$env:WINAPP_CLI_UPDATE_CHECK = "0"To make this permanent:
[System.Environment]::SetEnvironmentVariable('WINAPP_CLI_UPDATE_CHECK', '0', 'User')Inspect and interact with running Windows app UIs using UI Automation (UIA).
winapp ui [command] [options]Commands:
status- Connect to app and show infoinspect- View element treesearch- Find elements by selectorget-property- Read element propertiesget-text/get-value- Read value/text from element (TextPattern, ValuePattern, or Name)screenshot- Capture window/element as PNG (auto-captures dialogs separately)record- Record a window/element region to an H.264 MP4 video (Windows Graphics Capture + Media Foundation)invoke- Activate element (click, toggle, expand)click- Click element via mouse simulation (for controls that don't support invoke)hover- Move mouse to element to trigger tooltips, flyouts, and hover states (default dwell: 800ms)drag- Drag the mouse from one point to another, by element selector or screenx,ycoordinates (reorder, resize, sliders, drag-and-drop)touch- Inject synthetic touch gestures (tap, double-tap, long-press, swipe, pinch, stretch) at an element center or screenx,ycoordinatespen- Inject synthetic pen/stylus input — taps and ink strokes with configurable pressure, tilt, and eraser modesend-keys- Send synthetic keyboard input (named keys, combos, raw vk=0xNN, or literal text) to a windowset-value- Set value on editable element (text, number); falls back to LegacyIAccessibleput_accValuefor TextPattern-only rich-edit controlsfocus- Move keyboard focusscroll-into-view- Scroll element visiblewait-for- Wait for element statelist-windows- List all windows for an appget-focused- Report the currently focused element
Options:
-a, --app <app>- Target app (name, title, or PID)-w, --window <hwnd>- Target window by HWND (stable)
Record a window or element region to an H.264 MP4.
# Record a window for 10 seconds at 15 fps
winapp ui record -a Calculator --duration-sec 10 --fps 15 -o demo.mp4
# Record until Ctrl+C, downscaled so the longest edge is 1280px
winapp ui record -a "My App" --duration-sec 0 --max-edge 1280 -o capture.mp4
# Record just one element's region
winapp ui record -a "My App" btn-save-1234 -o button.mp4
# Keep an agent-readable timeline alongside the MP4
winapp ui record -a Calculator --frames --duration-sec 10 --fps 10 -o demo.mp4Record options:
--duration-sec <n>- Recording length in seconds.0records until Ctrl+C (default0).--fps <n>- Frames per second to capture (default15).--max-edge <px>- Downscale so the longest edge is at most this many pixels (0= no downscale).--capture-screen- Capture from the screen so overlays/popups are included (may capture occluding windows).-o, --output <path>- Output.mp4path (defaults torecording-<timestamp>-<guid>.mp4).--frames- Write timestamped JPEGs,frames.ndjson, andmanifest.jsonto<output-name>.frames. Supports 1-30 fps and--max-edge64-4096 (default 1280), with a 1 GiB frame-data cap.
With --json, the final result includes the output path, dimensions, codec, capture mode, cadence,
stop reason, optional frameArtifacts, and warnings.
Known limitation: recording a specific element inside a popup that renders in its own top-level window (WinUI/XAML flyout, teaching tip, tooltip) may capture the underlying main window instead. Record the whole window, or use
ui screenshot --capture-screenfor popup stills. Tracked in #646.
For full documentation, see docs/ui-automation.md.