A command-line tool for .NET MAUI development environment setup and device management.
⚠️ Experimental — APIs may change between releases. Not covered by the Microsoft Support Policy.
| Package | Description |
|---|---|
| Microsoft.Maui.Cli | Global CLI tool (maui) for environment setup, device management, and diagnostics. |
dotnet tool install -g Microsoft.Maui.Cli --prereleasemaui update --self
maui update --self --prerelease
maui update --self --dry-runThe --self flag explicitly targets the CLI. Bare maui update displays
guidance without updating anything; project updates are not implemented by
this command.
Self-update supports the default global .NET tool installation only, not
local tool manifests, custom --tool-path installs, or source builds.
Preview installations automatically include prereleases; stable installations
require --prerelease to include them. The SDK chooses the latest eligible
version; the command does not request downgrades.
Updates preserve the current directory's normal SDK selection (global.json)
and NuGet configuration. An installed .NET SDK is required; missing SDKs,
unreachable feeds, and permissions failures must be resolved before retrying.
No feeds or configuration files are changed.
Only run self-update from a trusted directory: repository-local NuGet.config
files can select feeds and influence the CLI package installed by the SDK.
To avoid a repository's configuration, run the command from a trusted directory
outside that repository. Public update notices do not validate or override the
feeds used for installation.
On Windows, the running tool cannot uninstall its own loaded package.
maui update --self starts a one-shot PowerShell handoff that waits for this process
to exit before running the SDK updater. In an interactive terminal, the updater
prints progress and a final completion or failure message in the same terminal.
The shell prompt may return before these messages appear. Started is not
completed: wait for the completion message before running the CLI again.
The printed log path also records SDK output and SDK_EXIT=0 on success if
you miss the terminal message. Keep the terminal open until completion;
closing it may interrupt the updater. A nonzero SDK_EXIT indicates failure. The updater waits at most one
minute for the original process to exit. On macOS/Linux the command waits for
the SDK and reports its result directly.
Existing --json, --ci, --verbose, and --dry-run flags apply. JSON reports
started with a log path for the Windows handoff, not a successful completed
installation; its exit code confirms handoff only. Dry-run invokes no updater
and performs no network checks or state writes. JSON, CI, and redirected
invocations receive no delayed terminal messages; use the log for completion.
Ordinary interactive commands can show an update notice after successful
completion. The first eligible invocation each UTC day checks listed versions on
NuGet.org through its version autocomplete service in-process, with a two-second
timeout covering service discovery and version retrieval; later invocations use a
small user cache. Failed attempts are cached too. There is no daemon or
notification subprocess. Checks are suppressed in CI, JSON, redirected
output, help, dry-run, and protocol/server commands. Set
MAUI_CLI_NO_UPDATE_CHECK=1 to disable checks and notices. Notifications use
public package metadata; actual updates still use your configured feeds.
# Run diagnostics
maui doctor
# List connected devices
maui device list# Preview recommended setup for VS Code, including destinations and scope
maui ai init --env VsCode --dry-run
# Install the recommended skills, agents, and MCP registration
maui ai init --env VsCode --yes
# Discover all supported asset kinds, then inspect this project's inventory
maui ai list
maui ai status
# Refresh only existing managed assets; missing recommendations are NOT added
maui ai updateAI assets are explicit: skills, agents, and MCP registrations. Adding a skill does not install an agent or configure MCP. Use init for recommended combined setup, or choose individual assets:
maui ai add skill maui-devflow-debug --env Claude --yes
maui ai list agent
maui ai add agent "Comet Squad" --env VsCode --yes
maui ai add mcp maui-devflow --env VsCode --yes
# Only these named assets; selecting a bundled skill does not install siblings
maui ai init --skill maui-devflow-debug --mcp maui-devflow --env Claude --yes
# Restrict inventory and updates to one kind and environment
maui ai status skill --env Claude
maui ai update skill --skill maui-devflow-debug --env Claude --yesRecommendations are explicit, not every catalog entry: the three bundled DevFlow skills, DevFlow MCP registration, the expert-reviewer agent, and the available maui-current-apis, maui-project-structure, maui-app-architecture, maui-ui-patterns, maui-unit-testing, and maui-accessibility skills. Only client-compatible recommendations are selected. Other catalog assets, including Comet-specific guidance, remain available through explicit selectors/add commands; adding an entry to the catalog does not automatically add it to init.
Human catalog output labels recommendations explicitly. Each command's --help
includes examples; [type] means an optional positional kind, not a required
option. Global --json, --ci, and --dry-run control CLI behavior, not
installation scope.
Run from the project you want to configure. In Git repositories, the Git root is the project boundary; outside Git, the current directory is used. Detected nested skill/configuration locations are honored. Copilot agents live in project .github/agents and support VS Code and Copilot CLI, not Claude Code or OpenCode.
| Command | Behavior and important options |
|---|---|
maui ai init |
Recommended combined setup. Repeatable --skill, --agent, and --mcp selectors instead install only their explicit union. Each bundled skill selector identifies one skill. |
maui ai list [type] |
Available assets, default all kinds; optional singular skill, agent, or mcp. Catalog discovery may use the network. |
maui ai status [type] |
Read-only installed/configured inventory, including unmanaged and tracked-but-missing assets. Not an MCP connectivity check. |
maui ai update [type] |
Refresh existing managed assets only, using recorded origins. Missing or unmanaged assets are not installed/adopted, even with force. Supports exact type-specific selectors. |
maui ai add skill <name> |
Install one skill through its owner (bundled DevFlow or repository). No implicit MCP or agent installation. |
maui ai add agent <name> |
Install one Copilot agent definition. |
maui ai add mcp <name> |
Merge a known server registration; currently maui-devflow. Does not install an executable, approve a client connection, or probe connectivity. |
All commands support repeatable --env Claude|VsCode|CopilotCli|OpenCode. An explicit kind/name plus explicit environments must be compatible in every requested pairing: add agent <name> --env Claude VsCode fails before writing instead of silently targeting only VS Code. Without explicit assets, combined setup/catalog/inventory includes applicable kinds for the chosen environments. Shared physical destinations are deduplicated while retaining client associations.
init and add --env can target a canonical environment before its marker directory exists. Without --env, the default is all detected environments, not Copilot. Setup explains the configuration markers or recorded installations that selected each client, together with destinations and scope. A marker is not proof that the client executable is installed or running. In particular, a user's ~/.copilot/ can select Copilot CLI even without a project Copilot marker.
Interactive init offers a client selector when none are detected. It never invents a default client. With --yes, --ci, --json, --dry-run, or redirected input, missing targets instead produce actionable --env guidance without prompting. Read-only commands and update never create environment directories. Preview setup explicitly when configuring a project for the first time:
maui ai init --env Claude --dry-run
maui ai init --env Claude --yes--yes (alias -y) accepts confirmation prompts only. --force authorizes replacement/adoption, not prompt acceptance; combine it with --yes for unattended replacement. For bundled DevFlow skills, force can also replace a newer CLI's content with the running CLI's bundle. Global --json and --ci suppress prompts but never authorize overwriting conflicts. CI stops later mutations after a failure. Customized or conflicting unmanaged assets require force and otherwise produce a blocked result/nonzero exit. Harmless already-current actions can skip successfully.
Global --dry-run never prompts or writes, including ownership/freshness state. It uses the same selection and conflict rules as execution and reports create/replace/adopt/skip actions, reasons, destinations, and project/user scope. Network access may still be required.
JSON command results use a versioned envelope with schemaVersion, command, dryRun, aggregate status, and results. Each result identifies the asset kind/name, associated environments, destination and scope, ownership, observed state, planned action, outcome, and reason. A successful inventory command is not a claim that every row is current or managed. Inspect row states and reasons; blocked actions and application failures produce nonzero exits.
The automation contract documents the JSON Schema, reason codes, exit semantics, compatibility rules, and the parser/cancellation cases outside the envelope.
MCP configuration uses .mcp.json for Claude Code, .vscode/mcp.json for VS Code, opencode.json (or existing .jsonc) for OpenCode, and user-wide ~/.copilot/mcp-config.json for Copilot CLI. Only the known definition's launch fields are managed; other servers, credentials, environment settings, and user options are preserved even under force. Malformed shared configuration remains an error, not permission to replace the whole file. An exact unmanaged registration is not silently adopted; use add mcp ... --force to opt into management. MCP update refreshes the registration definition, not the server executable version.
JSONC comments cannot be retained when a configuration is rewritten; the original is backed up to <config>.bak. This is a latest-only recovery file, not backup history: another comment-bearing rewrite replaces it. Copy it elsewhere before another rewrite if you need to retain that recovery point. Clients may require restart, project trust, or server approval before loading a registration. Inventory reports configuration and ownership, not connection health.
The default catalog is dotnet/maui-labs on main. Source overrides use --repo <owner/repo> and --branch <ref>; managed assets retain their recorded origin for later updates unless explicitly overridden. Missing required provenance is reported rather than guessed. Bundled versions refer to the running CLI's content, not remote downloads.
Each remote repository/ref is resolved once per plan to an immutable commit, so
catalog discovery and downloaded content cannot mix revisions when a branch
moves. Results report origin.resolvedCommit when a source is resolved, while
origin.branch retains the tracking ref. To reproduce remote selection across
separate preview/apply runs, pass the same full 40-character commit to --branch
and use the same CLI version. A commit-pinned installation stays pinned on update
unless its source is explicitly overridden; ordinary branches continue tracking
new commits. See the automation contract for pipeline examples and limitations.
Skills retain their existing owner metadata (.skill-version or DevFlow state). Agent/project MCP ownership uses .maui/ai-assets.json under the project root; user MCP ownership is separate under the user's .maui. Registries record identity, origin, and managed-content hashes, not raw credentials/configuration. These are mutable local installation records; consider excluding them from version control. Commands do not silently change .gitignore.
New DevFlow skill workspace IDs and custom-path target keys use 32 lowercase hex characters from SHA-256. Existing shorter state directories, target keys, and lock files stay in use so installed skills keep their ownership records. If both old and new state locations exist, the CLI stops instead of merging or replacing records. Resolve that conflict before continuing. Do not use an older CLI to manage a target first created with the longer state keys.
Breaking changes from earlier versions of this unmerged PR: use add skill <name> instead of add <name>; -y now means yes, not force; adding skills no longer configures MCP; selectors no longer expand bundled groups or target another kind; list defaults to all asset kinds; update never installs missing recommendations; JSON output uses the typed result envelope instead of the earlier command-specific arrays/records. No hook/canvas commands or executable stubs are provided.
Skill replacement stages downloads and restores the previous directory on ordinary write failures. It is not crash-atomic: interruption between directory renames can leave <skill>.<id>.bak alongside the skills directory. If the skill directory is missing, inspect that backup and rename it back before retrying. Concurrent installations into the same destination are not supported. Path/symlink checks are not handle-based isolation against concurrent filesystem changes; use trusted, locally controlled destinations. Repository-hosted Copilot agents are currently single-file assets; writes across multiple assets are not one transaction.
# Show the effective MAUI version for the current project
maui project version
maui project version --project ./src/MyApp/MyApp.csproj
# List available versions
maui project version list
maui project version list --channel nightly --take 20
# Pin a specific version and restore
maui project version set 10.0.60
# Use the latest stable or nightly package version
maui project version set --latest
maui project version set --latest-nightly --nuget-config
# Switch back to the installed workload version
maui project version use-workload# Full interactive Android setup (JDK + SDK + emulator)
maui android install
# Manage Android SDK packages
maui android sdk list
maui android sdk install "platforms;android-35"
# Ensure the latest Android command-line tools are installed
maui android sdk update-tools
maui android sdk update-tools --json
# Manage JDK installations
maui android jdk install
# Create and manage emulators
maui android emulator create --name MyEmulator
maui android emulator start --name MyEmulatorSDK package listing supports both the legacy sdkmanager table and the Android
CLI table produced by Command-line Tools 23. JSON retains
semicolon-separated package IDs, including dotted API levels such as
platforms;android-37.0. Installed Command-line Tools omitted by the inventory
are detected from their executable and source.properties revision.
Listed revisions are preserved when source.properties or its revision is
missing; unlisted tools without revision metadata keep an unknown version.
Inventory execution or parsing failures return an error rather than an empty
successful package list.
sdk update-tools checks Google's catalog and bootstraps or updates
cmdline-tools;latest as needed. It uses the configured SDK path (or the default
SDK location) and requires a working JDK. --dry-run only previews the target
path. JSON success reports status: "ready" whether the tools were already
current or were installed; it does not claim an update occurred.
maui doctor reports the selected tool's path and revision when available.
The resolver prefers cmdline-tools/latest, then the highest installed
command-line tools revision. Legacy tools/bin installations are no longer
supported; run maui android sdk update-tools to install modern tools.
# List installed Xcode versions
maui apple xcode list
# List simulator runtimes
maui apple runtime list
maui apple runtime list --platform iOS
# Manage simulators
maui apple simulator list
maui apple simulator start "iPhone 16 Pro"
maui apple simulator stop "iPhone 16 Pro"
maui apple simulator delete "iPhone 16 Pro"After adding the DevFlow agent to a running app:
maui devflow broker startThen open http://localhost:19223/inspector/. See the
MAUI DevFlow Inspector guide for app registration and browser,
VS Code, GitHub Copilot desktop, and Copilot CLI setup.
| Command | Description |
|---|---|
maui doctor |
Run environment diagnostics and auto-fix issues |
maui device list |
List connected devices, emulators, and simulators (including physical iPhones and iPads on macOS) |
maui project version |
Show the effective .NET MAUI version for a project |
maui project version list |
List available .NET MAUI package versions |
maui project version set |
Pin a project to a specific, latest stable, nightly, or custom-source MAUI version |
maui project version use-workload |
Use the installed MAUI workload version instead of a pinned project version |
maui version |
Display version information |
| AI | |
maui ai init |
Bootstrap MAUI/Copilot skills, bundled DevFlow skills, Copilot agents, and MCP configuration |
maui ai list [type] |
List available skills, agents, and MCP registrations |
maui ai status [type] |
Read-only installed/configured asset inventory |
maui ai update [type] |
Refresh existing managed assets only |
maui ai add skill <name> |
Install exactly one skill, without implicit MCP setup |
maui ai add agent <name> |
Install one Copilot agent |
maui ai add mcp <name> |
Configure one known MCP server registration |
| Android | |
maui android install |
Full interactive Android environment setup |
maui android sdk list |
List available and installed Android SDK packages |
maui android sdk install |
Install Android SDK packages |
maui android sdk check |
Check Android SDK installation status |
maui android sdk uninstall |
Uninstall Android SDK packages |
maui android sdk accept-licenses |
Accept Android SDK licenses interactively |
maui android sdk update-tools |
Ensure the latest Android SDK command-line tools are installed |
maui android jdk install |
Install and manage JDK versions |
maui android jdk check |
Check JDK installation status |
maui android jdk list |
List available JDK versions |
maui android emulator create |
Create an Android emulator |
maui android emulator start |
Start an Android emulator |
maui android emulator stop |
Stop a running emulator |
maui android emulator delete |
Delete an emulator |
maui android emulator list |
List available emulators |
| Apple (macOS only) | |
maui apple xcode list |
List installed Xcode versions |
maui apple runtime list |
List installed simulator runtimes |
maui apple simulator list |
List simulator devices |
maui apple simulator start |
Boot a simulator |
maui apple simulator stop |
Shut down a simulator |
maui apple simulator delete |
Delete a simulator |
| DevFlow | |
maui devflow init |
Install project-scoped DevFlow onboarding/debugging skills |
maui devflow skills |
Manage bundled DevFlow skill installs and updates |
maui devflow ui |
Visual tree inspection, interaction, and screenshots |
maui devflow device fold |
Foldable emulator/simulator modes, hinge angles, and verified transitions (iOS requires experimental opt-in) |
maui devflow ui diagnostics |
Detect clipping, overflow, text truncation, overlap, and occlusion |
maui devflow recording |
Manage UI recording sessions (start, stop, status) |
maui devflow webview |
Blazor WebView automation via Chrome DevTools Protocol |
maui devflow logs |
Fetch and stream application logs |
maui devflow network |
Monitor HTTP network requests |
maui devflow storage |
Access app preferences, secure storage, discover file storage roots, and manage sandboxed app files |
maui devflow agent |
Discover and inspect connected DevFlow agents |
maui devflow broker |
Manage the DevFlow agent broker (start, stop, status, log) |
maui devflow batch |
Execute commands from stdin for scripting; stop on failure by default. --continue-on-error runs later commands but still exits nonzero if any command fails. |
maui devflow commands |
List all available commands (schema discovery) |
maui devflow diagnose |
Check DevFlow agent health |
maui devflow wait |
Wait for an agent to connect |
maui devflow mcp |
Start the MCP server for AI agent integration |
| Profiling | |
maui profile startup |
Collect a startup trace for a .NET MAUI app (.nettrace, speedscope, or MIBC output) |
maui profile manual |
Launch a MAUI app normally, then attach and stop tracing on demand |
| Go | |
maui go create |
Create a new MAUI Go single-file project |
maui go serve |
Start the dev server with hot reload |
maui go upgrade |
Graduate a Go project to a full MAUI project |
maui go upgrade keeps the existing ASCII name rules for generated application IDs.
If the directory name has no ASCII letters or digits, a new ID uses com.cometgo.app
followed by the first 32 lowercase hex characters of SHA-256 of the UTF-8 directory name.
An explicit #:property ApplicationId=... remains unchanged.
For these directory names, upgrade refuses to overwrite an existing .csproj, even with
--force. Keep the existing project and its ApplicationId to preserve the app identity,
including IDs generated with the previous eight-character fallback.
Run maui <command> --help for detailed options on any command.
For screen recording, select the platform and target when starting:
maui devflow recording start --platform android --device <serial> --output capture.mp4
# Or: --platform ios --device <simulator-UDID>
maui devflow recording stopAn iOS simulator recording requires an explicit --device. Stopping uses the
saved recording platform and Android serial; it does not require repeating
--platform or --device, and those options do not override the saved target.
The iOS driver stops its saved recording process. Without a saved recording,
stop reports an error without creating a platform driver.
Profiling commands wait up to two minutes for dotnet-trace to finish rundown and flush after a manual, timed, or event-driven stop. Use --trace-stop-timeout to adjust that finalization window independently of --duration.
MIBC conversion uses the selected target framework and configuration's isolated build outputs, filtered to the app's runtime identifier (ABI). An explicit RuntimeIdentifier is honored; for multi-ABI builds, the selected device's runtime identifier chooses the references (iOS simulators without architecture metadata use the host architecture). RID-specific output paths are evaluated separately so SDK artifact layouts are supported. The evaluated build settings determine the assembly-processing stage: shrinking uses only shrunk, linking without shrinking uses only linked, and untrimmed builds use neither. Reference-only assemblies are excluded. Missing stage outputs or missing/ambiguous ABI information are reported as errors rather than falling back to another stage or ABI.
For the shared Inspector UI and its host integrations, see the MAUI DevFlow Inspector guide.
DevFlow file commands can use local files directly:
# Upload local bytes into the selected app storage root
maui devflow storage files upload logs/app.log --file ./app.log
# Download to a directory, preserving the device file name
maui devflow storage files download logs/app.log --output ./downloads/
# Download to an explicit local file name
maui devflow storage files download logs/app.log --output ./downloads/app-copy.logDevFlow WebView DOM and input helpers accept --webview (or -w) to select a
WebView by index, AutomationId, or element ID; omitting it selects the first
WebView. The cdp alias accepts the same options. The target is sent with the
request, not inserted into the generated JavaScript:
maui devflow webview webviews
maui devflow webview --webview Right DOM querySelector "#name"
maui devflow webview -w Right snapshot
maui devflow webview -w Right Input fill "#name" "Hello"
maui devflow webview -w Right Input dispatchClickEvent "#submit"
maui devflow webview -w Right Input insertText "More text"fill sets the matching field's value and dispatches input/change events;
insertText inserts at the cursor in the selected WebView. These DOM helpers
are separate from native ui query --selector and MCP maui_query_css.
| Option | Description |
|---|---|
--json |
Output in JSON format (for scripting and CI) |
-v, --verbose |
Enable verbose output |
--dry-run |
Show what would be done without making changes |
--ci |
CI mode — non-interactive, fail fast on errors |
The CLI supports two output modes:
- Interactive (default) — Rich Spectre.Console output with colors, tables, and progress bars
- JSON (
--json) — Machine-readable JSON for scripting and CI pipelines
# Human-friendly output
maui doctor
# JSON output for scripting
maui doctor --json | jq '.checks[] | select(.status == "failed")'Most commands accept --json for structured output. Some commands may emit multiple JSON objects to stdout (JSONL / newline-delimited JSON) — for example, progress or status records before the final result. The final JSON object is the command result, whose shape is command-specific (see per-command --help and examples below). When a non-DevFlow command fails and the exception is handled by HandleCommandException, it emits the canonical error envelope described in the next section. This applies to both recognized MauiToolException errors (which produce specific error codes) and unexpected exceptions (which become E1001/InternalError via ErrorResult.FromException). Note: unrecognized parse errors (e.g. invalid flags) do not use this envelope, OperationCanceledException produces a status message with exit code 130 rather than the error envelope, and maui devflow ... uses a different JSON contract and writes structured errors to stderr rather than stdout.
Use --ci together with --json for non-interactive, fail-fast runs in automation contexts. Parse the output as a stream of JSON objects rather than assuming a single top-level document.
Successful maui profile startup --json and maui profile start --json runs emit a final result with snake_case project, framework, platform, device, diagnostic, and timestamp fields. format identifies the output format and output_path points to the primary artifact; raw_trace_path is included for speedscope and MIBC output and omitted for nettrace output.
For non-DevFlow maui commands, when a command throws an exception that is handled by HandleCommandException and --json is active, it writes a structured error object to stdout. The fields appear at the top level — there is no enclosing "error" wrapper. Property names are snake_case. Note: some commands may return non-zero exit codes without throwing (e.g. validation paths), and OperationCanceledException is treated as a cancellation (exit code 130) rather than an error envelope. This section does not apply to maui devflow ..., which uses a different JSON error shape and writes structured errors to stderr.
{
"code": "E2106", // stable error code — see the error code table below
"category": "platform", // tool | platform | user | network | permission
"severity": "error", // always "error" today (info | warning reserved for future use)
"message": "Android emulator not installed",
// OPTIONAL — omitted entirely when null (never serialized as JSON null)
"native_error": "...", // raw error text from the underlying tool, when available
"context": { ... }, // command-specific diagnostics bag
"remediation": {
"type": "autofixable", // autofixable | useraction | terminal | unknown
"command": "maui android sdk install emulator", // present when type == autofixable
"manual_steps": ["...", "..."] // present when type == useraction
},
"docs_url": "https://...", // reserved — not yet populated by any command
"correlation_id": "..."
}Contract guarantees (verified line-by-line against Models/ErrorResult.cs):
- Property names are
snake_case— enforced by[JsonPropertyName]attributes onErrorResult. remediation.typevalues are lowercase strings — serialized via.ToString().ToLowerInvariant().- Optional fields (
native_error,context,remediation,docs_url,correlation_id) are omitted entirely when null — enforced by[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]. - There is no outer
"error"wrapper — all fields are top-level. code,category,severity, andmessageare always present.- The CLI intends to keep this envelope shape consistent; future changes are expected to be additive (e.g. new optional fields) rather than changing existing field names or types.
| Prefix | category value |
Examples |
|---|---|---|
E1xxx |
tool |
E1001 InternalError, E1004 InvalidArgument, E1006 DeviceNotFound, E1007 PlatformNotSupported |
E20xx |
platform |
E2001 JdkNotFound, E2002 JdkVersionUnsupported, E2003 JdkInstallFailed |
E21xx |
platform |
E2101 AndroidSdkNotFound, E2102 AndroidSdkManagerNotFound, E2103 AndroidLicensesNotAccepted, E2105 AndroidPackageInstallFailed, E2106 AndroidEmulatorNotFound, E2108 AndroidAvdCreateFailed, E2110 AndroidAdbNotFound, E2111 AndroidDeviceNotFound, E2112 AndroidAvdDeleteFailed |
E22xx |
platform |
E2201 AppleXcodeNotFound, E2202 AppleCltNotFound, E2203 AppleSimctlFailed, E2204 AppleSimulatorNotFound, E2205 AppleXcodeLicenseNotAccepted, E2206 AppleSetupFailed, E2207 AppleSimulatorCreateFailed, E2208 AppleSimulatorEraseFailed |
E23xx |
platform |
E2301 WindowsSdkNotFound |
E24xx |
platform |
E2401 DotNetNotFound, E2402 MauiWorkloadMissing, E2403 DiagnosticsToolNotFound |
E3xxx |
user |
User action required (wrong arguments, missing inputs) |
E4xxx |
network |
Download / connectivity failures |
E5xxx |
permission |
Privacy / OS permission issues |
A maui errors list command is planned (issue #197) to expose this catalogue at runtime. The table above is the authoritative list until then.
Bash / jq:
if ! out=$(maui android sdk install emulator --json 2>&1); then
# Output may contain multiple JSONL lines; extract the error envelope (has a "code" field)
err=$(echo "$out" | jq -s '[.[] | select(.code)] | last')
rem_type=$(echo "$err" | jq -r '.remediation.type // "unknown"')
rem_cmd=$(echo "$err" | jq -r '.remediation.command // empty')
if [[ "$rem_type" == "autofixable" && -n "$rem_cmd" ]]; then
# Run the remediation command directly (never pass untrusted input to eval)
$rem_cmd
fi
fiPowerShell:
$lines = maui android sdk install emulator --json
if ($LASTEXITCODE -ne 0) {
# Output may contain multiple JSONL lines; pick the error envelope (has a "code" property)
$err = $lines | ForEach-Object { $_ | ConvertFrom-Json } |
Where-Object { $_.code } | Select-Object -Last 1
if ($err.remediation.type -eq 'autofixable' -and $err.remediation.command) {
# Split and invoke directly (avoid Invoke-Expression with untrusted input)
$parts = $err.remediation.command -split ' '
& $parts[0] $parts[1..($parts.Length-1)]
}
}maui android emulator start <name> emits E2106 with an autofixable remediation when the Android emulator binary is not installed:
maui android emulator start Pixel8 --json
# → { "code": "E2106",
# "category": "platform",
# "severity": "error",
# "message": "Android emulator not installed",
# "remediation": { "type": "autofixable",
# "command": "maui android sdk install emulator" } }
# Auto-fix path:
maui android sdk install emulator --json
maui android emulator start Pixel8 --json # retry originalOther E2106 throw sites (e.g., "no AVD with that name") emit the same code without a remediation block — surface message and stop retrying.
For agent-facing usage examples and remediation patterns used by AI coding agents, see
maui-devflow-debug troubleshooting.
For Inspector reconnect behavior, control handoff, and XAML workspace recovery, see Inspector recovery and source editing.
| Platform | Status | Notes |
|---|---|---|
| macOS | ✅ | Full support including Apple commands (Xcode, simulators, runtimes) |
| Windows | ✅ | Android SDK, JDK, and emulator commands |
| Linux | ✅ | Android commands |
DevFlow command registration, argument validation, presentation, exit codes, and batch
parser re-entry live in DevFlowCommands. Internal instance operations under the
DevFlow/Operations/ directory own native UI, WebView/CDP, storage/device, streaming, theme,
extensions, capture/recording, host alerts/permissions, and broker/discovery execution.
Command-side helpers prepare and own agent connections; operations borrow clients and
do not dispose them. Stream cancellation subscriptions and rendering stay at the CLI boundary.
# Open just the CLI in your IDE
open src/Cli/Cli.slnf
# Build
dotnet build src/Cli/Cli.slnf
# Run tests
dotnet test src/Cli/Microsoft.Maui.Cli.UnitTests/Microsoft.Maui.Cli.UnitTests.csproj
# Run locally without installing
dotnet run --project src/Cli/Microsoft.Maui.Cli/ -- doctor