winapp-setup

作者: microsoft

为MSIX打包、Windows SDK访问或Windows API使用设置Windows应用项目。在向Electron、.NET、C++、Rust等添加Windows支持时使用。

npx skills add https://github.com/microsoft/winappcli --skill winapp-setup

When to use

Use this skill when:

  • Scaffolding a brand-new WinUI 3 app from an official Windows App SDK template (winapp new)
  • Adding Windows platform support to an existing project (Electron, .NET, C++, Rust, Flutter, Tauri, etc.)
  • Cloning a repo that already uses winapp and need to restore SDK packages
  • Updating SDK versions to get the latest Windows SDK or Windows App SDK

Prerequisites

Install the winapp CLI before running any commands:

# Via winget (recommended for non-Node projects)
winget install Microsoft.WinAppCli --source winget

# Via npm (recommended for Electron/Node projects — includes Node.js SDK)
npm install --save-dev @microsoft/winappcli

You need an existing app project — winapp init does not create new projects, it adds Windows platform files to your existing codebase.

Already have a Package.appxmanifest? .NET projects that already have a packaging manifest (e.g., WinUI 3 apps or projects with an existing MSIX packaging setup) likely don't need winapp init. Ensure your .csproj references the Microsoft.WindowsAppSDK NuGet package and has the right properties for packaged builds (e.g., <WindowsPackageType>MSIX</WindowsPackageType>). WinUI 3 apps created from Visual Studio templates are typically already fully configured — you can go straight to building and using winapp run or winapp package.

Key concepts

Package.appxmanifest is the most important file winapp creates — it declares your app's identity, capabilities, and visual assets. Most winapp commands require it (package, run, cert generate --manifest).

winapp.yaml is only needed for SDK version management via restore/update. Projects that already reference Windows SDK packages (e.g., via NuGet in a .csproj) can use winapp commands without it.

.winapp/ is the local folder where SDK packages and generated projections (e.g., CppWinRT headers) are stored. This folder is .gitignored — team members recreate it via winapp restore.

Usage

Create a new WinUI app

To start a brand-new WinUI app (rather than adding Windows support to an existing project), use winapp new. It verifies the .NET SDK, installs the official WinUI dotnet new template pack on demand (grabbing the latest, or offering to update a stale one), and scaffolds the app against your installed SDK's target framework. Most WinUI templates already include packaging/identity, so no winapp init step is needed afterward — follow the template-specific next step winapp new prints when it finishes. App templates go straight to winapp run (which builds and launches the app); the winui-lib (class library) and winui-unittest templates differ (reference the library from an app project, or winapp run the packaged test app to run its tests). The template list is read live from the installed pack — run winapp new --list to see the current set.

The pack ships two styles of app. XAML templates (winui, winui-navview, winui-tabview, winui-mvvm) define the UI in markup with a C# code-behind. Reactor templates (reactor, reactor-mvu, reactor-navview, reactor-tabview) are pure C# with no XAML, using an MVU pattern.

Reactor templates are experimental. They reference the prerelease Microsoft.UI.Reactor packages, whose APIs can change or be removed in a future release — don't pick one unless the user explicitly asks for Reactor. winapp new marks them (Experimental) in --list and in the picker, reports "Experimental": true in --json, and never selects one as the default. They also require the .NET 10 SDK or newer; on an older SDK winapp new fails up front naming the version it needs.

A first run, template-pack update, or newly published Windows App SDK version may take longer while missing NuGet packages download and restore. If scaffolding continues beyond 10 seconds, winapp new updates its status message rather than silently waiting.

# Interactive — pick a template, then name/output
winapp new

# See the available templates without scaffolding
winapp new --list

# One-shot with a specific template (short names come from `winapp new --list`)
winapp new --name MyApp --template winui-navview

# Experimental Reactor app (pure C#, no XAML) — requires the .NET 10 SDK
winapp new --name MyApp --template reactor-mvu

# Diagnose a failed scaffold: --verbose streams dotnet new's post-creation actions
# (restore, package add, etc.) live so the underlying dotnet error is visible
winapp new --name MyApp --verbose

# Always use the newest template pack without prompting
winapp new --name MyApp --template-version latest --use-defaults

# Non-interactive (agent) with machine-readable output
winapp new --use-defaults --name MyApp --json

Initialize a new winapp project

# Interactive — prompts for app name, publisher, SDK channel, etc.
# Automatically searches for compatible projects (Tauri, Electron, .NET, Rust, C++, Flutter)
winapp init

# Non-interactive — accepts all defaults (stable SDKs, current folder name as app name)
winapp init . --use-defaults

# Non-interactive with JS bindings enabled
winapp init . --use-defaults --add-js-bindings

# Skip SDK installation (just manifest + config)
winapp init . --use-defaults --setup-sdks none

# Install preview SDKs instead of stable
winapp init . --use-defaults --setup-sdks preview

After init, your project will contain:

  • Package.appxmanifest — package identity and capabilities
  • Assets/ — default app icons (Square44x44Logo, Square150x150Logo, etc.)
  • winapp.yaml — SDK version pinning for restore/update
  • .winapp/ — downloaded SDK packages and generated projections
  • .gitignore update — excludes .winapp/ and devcert.pfx

When JS bindings are enabled (via --add-js-bindings or by answering yes in interactive init), npm/Electron projects also get:

  • .winapp/bindings/ — generated JS bindings for Windows App SDK APIs (npm-only, Node / Electron)
  • package.json update — adds the winapp.jsBindings namespace and @microsoft/dynwinrt dependency (npm-only)

Initialize a sparse identity package (existing exe)

Use --sparse when you have an already-built desktop exe (WPF, WinForms, Win32, Electron, etc.) and only want to give it package identity — without repackaging the whole app into the MSIX. The app's files stay where they are and are resolved from an external content location at runtime.

# Generate an identity-only sparse manifest for an existing exe
winapp init --exe ./bin/Release/MyApp.exe --sparse

# Non-interactive, with explicit identity values
winapp init --exe ./bin/Release/MyApp.exe --sparse --name MyApp --publisher "CN=Contoso" --use-defaults

--sparse requires --exe. It skips all SDK/package installation (sparse identity packages have no SDK dependencies) and, by default, writes to a dedicated sparse/ folder in the current directory (override with --output-dir) so the manifest and its Assets/ stay out of a build-output folder that a rebuild would wipe:

  • appxmanifest.xml — identity-only sparse manifest (declares uap10:AllowExternalContent)
  • Assets/ — placeholder visual assets (extracted from the exe's icon when possible), resolved from the external location at runtime — not bundled into the .msix

If an appxmanifest.xml already exists in the target directory, init fails instead of overwriting it; re-run with --force to regenerate.

This is step 1 of the sparse packaging workflow. Continue with:

  1. winapp pack ./sparse/appxmanifest.xml --cert ./devcert.pfx — build the signed identity .msix
  2. winapp embed-identity ./bin/Release/MyApp.exe — connect the exe to the identity package (re-sign the exe afterward)
  3. Register in your installer with Add-AppxPackage -Path <msix> -ExternalLocation <install-dir>

For the full walkthrough, see the Sparse packaging guide.

Restore after cloning

# Reinstall SDK packages from existing winapp.yaml (does not change versions)
winapp restore

# Restore into a specific directory
winapp restore ./my-project

Use restore when you clone a repo that already has winapp.yaml but no .winapp/ folder. For a .NET project there is no winapp.yaml, so restore runs dotnet restore instead.

Private or custom NuGet feeds

init, restore, and update download the SDK packages through NuGet, honoring your standard nuget.config hierarchy. Private feeds and mirrors, feed credentials (including credential providers), and a custom globalPackagesFolder all work as they do for dotnet restore. To use only your feed, <clear /> the inherited sources first:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <clear />
    <add key="contoso" value="https://pkgs.dev.azure.com/contoso/_packaging/winsdk-mirror/nuget/v3/index.json" />
  </packageSources>
</configuration>

Security note: For native projects winapp resolves nuget.config from the directory it operates on: the init/restore directory argument, --config-dir when given, otherwise the current directory. For .NET projects the sources come from the project's own nuget.config hierarchy instead, because that is what dotnet add package and dotnet restore use — so put a private feed's config in the project directory or an ancestor, not in a sibling passed via --config-dir (that is reported and ignored). Run these commands only against directories you trust, the same as dotnet restore. Use <packageSourceMapping> to pin packages to specific feeds when more than one source is configured.

Update SDK versions

# Check for and install latest stable SDK versions
winapp update

# Switch to preview channel
winapp update --setup-sdks preview

This updates winapp.yaml with the latest versions and reinstalls packages.

Run and debug with identity

# Register debug identity and launch app from build output
winapp run ./bin/Debug

# Launch with custom manifest and pass arguments to the app
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

# Register identity without launching (useful for attaching a debugger manually)
winapp run ./bin/Debug --no-launch

# Launch and capture OutputDebugString messages and crash diagnostics
# Note: prevents other debuggers (VS, VS Code) from attaching — use --no-launch if you need those instead
winapp run ./bin/Debug --debug-output

Use winapp run during iterative development — it creates a loose layout package, registers a debug identity, and launches the app in one step. For identity-only registration without loose layout, use winapp create-debug-identity instead.

Project mode: winapp run on a .csproj (.NET / WinUI)

For .NET SDK projects you can point winapp run at the project instead of the build output — it builds the .csproj and launches it in one step, so there's no separate dotnet build and no need to know the output path:

# Build and run the project in the current directory (input defaults to ".")
winapp run

# Run a specific project, configuration, and architecture
winapp run ./src/MyApp/MyApp.csproj -c Release --arch arm64

# Force an unpackaged run of a packaged project
winapp run . -p WindowsPackageType=None

# Show winapp's build decision traces (dotnet build stays at minimal verbosity)
winapp run . --verbose

# Test a project configured with <PublishAot>true</PublishAot>
winapp run . --aot
winapp run . --aot -c Release

Project mode supports both packaged and unpackaged WinUI apps, detected from the project's effective WindowsPackageType (MSIX ⇒ loose-layout register + AUMID launch; None ⇒ launch the built .exe), and installs the matching-architecture Windows App Runtime before launching. RID-only remains the default; when the effective configuration requires a self-contained profile, winapp selects the architecture-matching profile without forcing that platform onto referenced AnyCPU libraries. Requires .NET SDK 8.0.100+.

  • Build inputs: -c/--configuration, --arch, -r/--runtime, -f/--framework, --no-build, --no-restore, --aot, -p/--property (repeat for multiple properties; use %3B or %2C for a literal semicolon or comma in a value). --aot supports x64/ARM64 projects, requires effective PublishAot=true, and cannot use --no-build or --manifest; configure the project manifest before publishing.
  • Packaged-only options: --manifest, --no-launch, --with-alias, --clean, --unregister-on-exit, --output-appx-directory, --executable — rejected for unpackaged apps.
  • Output: winapp restores dependencies, builds, and streams both commands' output live (including successful-build warnings). Restore output uses sanitized plain lines; interactive terminals show dotnet's in-place build progress when no build-time restore is needed, while other build output uses sanitized plain lines. --json sends restore/build invocations and child output to stderr so stdout stays valid JSON. --quiet suppresses invocations and sends dotnet's quiet restore/build output to stderr so stdout stays clean. With --aot, --verbose adds the publish command and resolved paths; publish diagnostics go to stderr under --json/--quiet.

Single-file mode: winapp run on a .cs file-based app

A .NET 10 file-based app is a single .cs file configured by #: directives, with no project file. Point winapp run at it and the app builds and launches with package identity — no hand-written manifest:

# Build and run a file-based app with identity
winapp run counter.cs

# Register identity without launching, or run a Release build detached
winapp run counter.cs --no-launch
winapp run counter.cs -c Release --detach --json

# Remove the package it registered
winapp unregister counter.cs

Describe the package with #:property directives in the file. All are optional:

PropertySetsDefault
WinAppPackageNameIdentity/@Namefile name (sanitized) + a short hash of its path
WinAppDisplayNameStart/Settings namefile name
WinAppPublisherIdentity/@PublisherCN=<current user>; a bare name is wrapped as CN=
WinAppVersionIdentity/@Version$(Version), normalized to four 0–65535 parts (1.2.3-preview.4 ⇒ 1.2.3.0)
WinAppDescriptionInstall/Settings descriptionthe display name
WinAppCapabilitiesCapabilities to declare, separated by ; or ,none
WinAppRunUseExecutionAliasLaunch via execution alias instead of AUMID, so console output stays in the terminaltrue for OutputType=Exe, else false
  • Capabilities for gated APIs. Running full trust with identity is enough for APIs that only require a packaged identity, but some are gated on a declared capability regardless — the Windows AI APIs most notably. (Shell integrations like protocol handlers and file associations are a separate thing again: those need authored <Extensions> entries, not a capability.) #:property WinAppCapabilities=systemAIModels is all Phi Silica needs from the manifest. winapp writes each name into the element and namespace it actually requires (<systemai:Capability>, <Capability>, <DeviceCapability> — they differ), declares that namespace, and raises MaxVersionTested when required. An unknown bare name is rejected rather than guessed; qualify it yourself with rescap:, uap:, systemai:, device: or app: (the app: set is closed at the five foundation capabilities).

  • Bring your own manifest with --manifest, #:property WinAppManifestPath=…, or a manifest next to the .cs named <filename>.appxmanifest. Only that per-file name is auto-detected — a shared Package.appxmanifest in the folder is ignored, since several .cs files can live together. Otherwise one is generated into the build output (with default assets) and refreshed each run.

  • Packaged and unpackaged both work, from the effective WindowsPackageType — same as project mode. None builds, installs the Windows App Runtime, and launches the .exe directly; identity options apply to packaged apps only.

  • Console apps print to the terminal by default. An app with OutputType=Exe is launched through an execution alias rather than AUMID activation, because an AUMID-launched packaged app has no console and would print nothing. Pass --without-alias (or set #:property WinAppRunUseExecutionAlias=false) to force AUMID; pass --with-alias to get one for a windowed app. The alias is named from the package family name with a winapp- prefix (com.contoso.counter → winapp-com.contoso.counter_<publisherhash>.exe), so it can never contend with a real command on PATH or with another publisher's same-named app; winapp run prints the name it registered. An authored manifest's own alias is used as-is. If another package already owns the name, winapp reports it — falling back to AUMID when it inferred the alias for you, and failing the run when you asked for one explicitly with --with-alias or WinAppRunUseExecutionAlias=true, rather than launching the wrong app.

  • Rejected options (the file configures itself): -f ⇒ #:property TargetFramework=…; --project ⇒ not applicable. --arch/-r work as in project mode and default to the current winapp process architecture — required for self-contained WinAppSDK apps, which fail as AnyCPU. Everything else works as usual.

  • The package outlives the run. winapp says so the first time it registers an app. Remove it with winapp unregister counter.cs (no manifest path needed — it resolves the same identity), or run with --unregister-on-exit.

  • dotnet run counter.cs works too. Add #:package Microsoft.Windows.SDK.BuildTools.WinApp@* and a Windows TFM (#:property TargetFramework=net10.0-windows10.0.19041.0) and the package's targets redirect the run to winapp — same packaged launch, no rebuild, no winapp command. A plain net10.0 file or #:property WindowsPackageType=None is left alone and runs unpackaged; #:property EnableWinAppRunSupport=false opts out. Diagnose with dotnet build counter.cs -t:WinAppRunSupportInfo (dotnet msbuild cannot load a .cs).

  • Requires .NET SDK 10.0.300+.

The default identity includes a short hash of the file's path (counter.cs → counter-a1b2c3d4), so two counter.cs files in different folders are separate apps with separate LocalState. It is stable across edits and re-runs, and changes only if the file moves. Set WinAppPackageName to pick a stable identity yourself. The Start menu shows WinAppDisplayName, not the identity.

Choosing between run and create-debug-identity

winapp runcreate-debug-identity
RegistersFull loose layout package (entire folder)Sparse package (single exe)
App launchWinapp launches via AUMID or aliasYou launch the exe yourself
Simulates MSIXYes — closest to productionNo — identity only
FilesCopied to AppX layout dirExe stays in place
Best forMost frameworks (.NET, C++, Rust, Flutter, Tauri)Electron, or F5 startup debugging

Default to winapp run. Use create-debug-identity when you need your IDE to launch and debug the exe directly (startup debugging), or when the exe is separate from your source (Electron).

Console apps keep stdin/stdout in the current terminal automatically: winapp reads the app's output type — from the project or .cs file where it can, and from the built binary's PE subsystem when running a build-output folder. Pass --with-alias only to force it for a windowed app, or when a folder holds several executables and detection can't pick one.

--debug-output caveat: Captures OutputDebugString and crash diagnostics (minidump + automatic analysis for both managed and native crashes) but attaches winapp as the debugger — you cannot also attach VS Code or WinDbg. Use --no-launch if you need your own debugger. Add --symbols to download PDB symbols for richer native crash analysis. For WinUI 3 apps, a stowed-exception triage pass runs automatically (surfacing the originating HRESULT and native XAML dispatch stack); the debugger components it needs are downloaded on first use, or set WINAPP_DBGTOOLS_DIR to a directory containing dbgeng.dll and JsProvider.dll for offline/locked-down environments.

For full debugging scenarios and IDE setup, see the Debugging Guide.

Recommended workflow

  1. Initialize — winapp init . --use-defaults in your existing project
  2. Configure — edit Package.appxmanifest to add capabilities your app needs (e.g., runFullTrust, internetClient)
  3. Build — build your app as usual (dotnet build, cmake, npm run build, etc.)
  4. Run with identity — winapp run ./bin/Debug to register identity and launch for debugging
  5. Package — winapp package ./bin/Release --cert ./devcert.pfx to create MSIX

Tips

  • Use --use-defaults (alias: --no-prompt) in CI/CD pipelines and scripts to avoid interactive prompts. Non-interactive environments (piped stdin, CI runners) are auto-detected and will use defaults automatically with a warning.
  • If you only need Package.appxmanifest without SDK setup, use winapp manifest generate instead of init
  • winapp init is idempotent for the config file — re-running it won't overwrite an existing winapp.yaml unless you use --config-only
  • For Electron projects, prefer npm install --save-dev @microsoft/winappcli and use npx winapp init instead of the standalone CLI

Related skills

  • After setup, see winapp-manifest to customize your Package.appxmanifest
  • Ready to package? See winapp-package to create an MSIX installer
  • Need a certificate? See winapp-signing for certificate generation
  • Not sure which command to use? See winapp-troubleshoot for a command selection flowchart

Troubleshooting

ErrorCauseSolution
"winapp.yaml not found"Running restore/update without configRun winapp init first, or ensure you're in the right directory
"Directory not found"Target directory doesn't existCreate the directory first or check the path
SDK download failsNetwork issue or firewallEnsure internet access; check proxy settings
SDK download fails with 401/403Private feed requires authenticationStore credentials in nuget.config (<packageSourceCredentials>) or configure a credential provider / feed environment credentials before running in CI
SDK package not found on private feedFeed doesn't mirror the SDK packages, or the wrong source is configuredEnsure the feed serves Microsoft.WindowsAppSDK, Microsoft.Windows.SDK.CPP, Microsoft.Windows.CppWinRT, etc.; keep nuget.org enabled if the feed only supplements it
init prompts unexpectedly in CIMissing --use-defaults flagAdd --use-defaults to skip all prompts (note: non-interactive shells are now auto-detected)
winapp new fails during scaffoldingA dotnet new post-creation action (restore, package add) failedRe-run with --verbose to stream the live dotnet output and see the underlying error

CLI reference

Run winapp <command> --help for current command options, or winapp --cli-schema for the complete machine-readable command schema.

来自 microsoft 的更多技能

oss-growth
microsoft
OSS增长黑客角色
agent-framework-azure-ai-py
microsoft
使用Microsoft Agent Framework Python SDK(agent-framework-azure-ai)构建Azure AI Foundry代理。在创建使用AzureAIAgentsProvider的持久化代理、使用托管工具(代码解释器、文件搜索、网络搜索)、集成MCP服务器、管理对话线程或实现流式响应时使用。涵盖函数工具、结构化输出和多工具代理。
development
airunway-aks-setup
microsoft
在AKS上设置AI Runway——从裸集群到运行模型。涵盖集群验证、控制器安装、GPU评估、提供商设置和首次部署。适用场景:“设置AI Runway”、“接入AKS集群”、“安装AI Runway”、“airunway设置”、“将模型部署到AKS”、“在AKS上进行GPU推理”、“在AKS上配置KAITO”、“在AKS上运行LLM”、“在AKS上使用vLLM”、“在AKS上设置模型服务”、“AI Runway控制器”。
devops
appinsights-instrumentation
microsoft
使用Azure Application Insights对Web应用进行插桩的指南。提供遥测模式、SDK设置和配置参考。适用场景:如何对应用进行插桩、App Insights SDK、遥测模式、什么是App Insights、Application Insights指南、插桩示例、APM最佳实践。
devops
applicationinsights-web-ts
microsoft
使用Application Insights JavaScript SDK(@microsoft/applicationinsights-web)为浏览器/Web应用添加检测。用于真实用户监控(RUM)——页面视图、点击、AJAX/fetch依赖项、异常、自定义事件,以及与后端OpenTelemetry追踪关联的浏览器端GenAI代理追踪。涵盖SDK加载器脚本和npm设置、框架扩展(React、React Native、Angular)、点击分析、遥测初始化器,以及从浏览器发出的代理/工具/模型跨度所遵循的OTel GenAI语义约定。
devops
azure-ai-anomalydetector-java
microsoft
使用适用于 Java 的 Azure AI 异常检测器 SDK 构建异常检测应用程序。在实现单变量/多变量异常检测、时间序列分析或 AI 驱动的监控时使用。
development
azure-ai-language-conversations-py
microsoft
使用azure-ai-language-conversations Python SDK实现对话语言理解(CLU)。当使用ConversationAnalysisClient分析对话意图和实体、构建NLP功能或将语言理解集成到应用程序中时使用。
development
azure-ai-ml-py
microsoft
Azure Machine Learning SDK v2 for Python。用于机器学习工作区、作业、模型、数据集、计算资源和管道。 触发词:“azure-ai-ml”、“MLClient”、“工作区”、“模型注册表”、“训练作业”、“数据集”。
development