- name
- reactor-app
- description
- Create WinUI 3 desktop applications using the Reactor framework — a React-inspired declarative C# projection over WinUI 3. No XAML, no data binding, no templates. This file is the legacy single-file skill — prefer the `reactor` plugin under `plugins/reactor/` (or `agentkit/plugins/reactor/` in the NuGet) for a more efficient skill-loading experience.
# Reactor — Getting Started
> **Prefer the plugin.** This file is preserved for environments that don't
> support the Copilot CLI / Claude plugin loading model. If you have a plugin
> SDK available, install / load the `reactor` plugin (under
> `plugins/reactor/` in source, or `agentkit/plugins/reactor/` in the NuGet).
> The plugin splits this content into focused per-skill files and is materially
> cheaper to load than this monolith.
Reactor is a **React-inspired functional projection for WinUI 3**. You write
functions that return lightweight element descriptions; a reconciler diffs
old vs new trees and patches real WinUI controls. State changes trigger
re-renders automatically. No XAML. No data binding. No ViewModels.
## Which mode are you in? (read this first)
Reactor ships as a NuGet package — apps reference it as
`<PackageReference Include="Microsoft.UI.Reactor" Version="…" />` (or
`#:package Microsoft.UI.Reactor@…` for single-file). The package carries
the framework, the analyzers, and an **agent kit** (signatures index +
this SKILL.md). Two paths:
| Mode | How to detect | Bootstrap |
|---|---|---|
| **Selfhost** — you're in a Reactor source clone (`src/Reactor/Reactor.csproj` exists) | The repo's `local-nupkgs/` folder is the package source — see `nuget.config` at repo root. | Build `mur` once, then **`mur pack-local`** to populate `local-nupkgs/Microsoft.UI.Reactor.0.0.0-local.nupkg`. Re-run after framework changes. |
| **Consumer** — you're in an app that depends on Microsoft.UI.Reactor | No `src/Reactor/` next to your project. | Nothing extra — the package already carries the analyzers and agent kit. If `mur` is on PATH, `mur --skill` and `mur --api` print the embedded docs. Otherwise read `<package-cache>/microsoft.ui.reactor/<version>/agentkit/`. |
If you're in selfhost and `local-nupkgs/` is empty, restore will fail with
"package Microsoft.UI.Reactor 0.0.0-local was not found." Run `mur pack-local`
to fix it.
### Bootstrap (selfhost, fresh clone)
```powershell
# Build the CLI; on first build the SignaturesGen project also writes
# skills/reactor.api.txt as part of its AfterBuild target.
dotnet build src/Reactor.Cli -p:Platform=ARM64
# `mur` mirrors itself to <repo>/bin/<arch>/. Add that to PATH or invoke directly.
.\bin\arm64\mur.exe pack-local
```
After this, any project under the clone resolves
`Microsoft.UI.Reactor 0.0.0-local` from `local-nupkgs/` automatically (the
repo-level `nuget.config` configures it). A consumer **outside** the clone
needs a project-local `nuget.config` pointing at the absolute path of
`<repo>/local-nupkgs/`.
## Where to find docs (`mur --skill`, `mur --api`)
The `mur` CLI ships these embedded — works from any directory:
| Command | What it prints | Source |
|---|---|---|
| `mur --skill` | This SKILL.md | embedded in `mur` |
| `mur --api` | The signatures index (≈70K tokens: every factory/modifier/hook/Theme token/enum, plus ctors/properties/methods/events on every public type — including static classes like `ControlRegistry` and `ReactorApp`) | embedded in `mur` |
| `mur --regen-api` | Rebuilds `skills/reactor.api.txt` from a freshly-built `Reactor.dll` (selfhost only) | rebuilds `tools/Reactor.SignaturesGen` |
| `mur check <path>` | **Is** the build (same exit code as `dotnet build`); adds one-line diagnostics with skill pointers for known REACTOR_* IDs and `→ try:` did-you-mean suggestions | wraps MSBuild |
A consumer who doesn't have `mur` can read the same files directly from the
NuGet cache:
```
%USERPROFILE%\.nuget\packages\microsoft.ui.reactor\<version>\agentkit\
├─ SKILL.md ← this file
├─ reactor.api.txt ← signatures index
└─ skills\
├─ async.md, design.md, commanding.md, navigation.md, forms.md,
│ input.md, charts.md, dsl-reference.md, devtools.md, perf-tips.md
└─ recipes\
├─ index.md ← intent → recipe map
└─ <name>.cs ← paste-ready single-file programs
```
When SKILL.md or a recipe references `skills/foo.md`, a consumer agent
reads it from `agentkit/skills/foo.md` in the package cache. Selfhost
agents read it from `<repo>/skills/foo.md`.
## API signatures index — load this before grepping source
[`skills/reactor.api.txt`](skills/reactor.api.txt) is a generated, alphabetized
flat list of every public Factory, Modifier, Hook, Theme token (with WinUI
resource key), and enum in Reactor. **Load this when you need to confirm a
signature.** It replaces grepping `src/Reactor/Elements/*.cs` and walking the
sub-skills' tables.
- **Local / selfhost:** the file is committed at `skills/reactor.api.txt`.
Run `mur --api` to print it. Run `mur --regen-api` after framework changes.
- **NuGet consumer:** the same file ships in the package at
`<package-cache>/microsoft.ui.reactor/<version>/agentkit/reactor.api.txt`
(typically `%USERPROFILE%\.nuget\packages\microsoft.ui.reactor\<version>\agentkit\reactor.api.txt`).
If `mur` is on PATH, `mur --api` prints the embedded copy.
## Recipes — paste-ready snippets indexed by intent
[`skills/recipes/`](skills/recipes/) holds compilable single-file recipes for
the most common Reactor patterns. **Load a recipe instead of synthesizing
from skill prose.** See [`skills/recipes/index.md`](skills/recipes/index.md)
for the intent → recipe map. Available today: list-add-delete, sidebar-nav,
form-with-validation, async-fetch-list, themed-card, canvas-positioning,
named-styles, calendar-multiselect.
## Wrapping native / third-party controls (source generator)
Need a control Reactor has no built-in factory for (a vendor control or your own
custom `Control`)? Annotate an empty partial record and the
`[GenerateReactorWrapper]` source generator emits the element, descriptor,
registration, and a factory named after the control — no hand-written wrapper:
```csharp
using Microsoft.UI.Reactor.Wrappers;
[GenerateReactorWrapper(typeof(Acme.Controls.RatingDial))]
public partial record RatingDialElement; // → using static …RatingDialElement; RatingDial(value: …, onValueChanged: …)
```
Full guidance — auto-inference, the `[Wrap*]` annotation cheat-sheet, imperative
lifecycle, diagnostics, and a gallery of worked examples — is in the
`reactor-wrapping` skill (`plugins/reactor/skills/reactor-wrapping/`, or
`agentkit/plugins/reactor/skills/reactor-wrapping/` in the nupkg). Spec:
`docs/specs/058-control-wrapper-generator.md`.
## `mur check` — fast feedback with skill pointers
**`mur check` is the build, not a separate check step.** It runs `dotnet build`
under the hood and returns the same exit code. When `mur check` exits 0, the
build is green — **do not re-run `dotnet build` to confirm**. They're the same
compilation; a redundant `dotnet build` afterwards is wasted work.
Two enrichments over raw `dotnet build`:
1. **Skill pointers** for known `REACTOR_*` IDs.
2. **Did-you-mean `→ try:` suggestions** for unknown identifiers, computed against
the live Reactor surface for the exact diagnostic.
```
C:\path\Program.cs:15:23 W REACTOR_DSL_001 Element produced by Select(...)… → SKILL.md gotcha #6 (.WithKey on dynamic list items)
C:\path\Program.cs:34:16 E CS1061 'ButtonElement' does not contain a definition for 'OnClick' → try: Button(label, onClick: ...) // [factory has Action onClick parameter]
```
`<path>` defaults to `.` and accepts a `.csproj` or directory. Single-file
`.cs` builds work but **don't load analyzers** — for analyzer coverage,
use a `.csproj`.
**Trust `→ try:` suggestions directly.** Use the suggested name verbatim in your
next edit; don't grep adjacent or sibling names to second-guess it. The
suggestion has been computed against the actual Reactor surface for this exact
diagnostic. If wrong, the next `mur check` will tell you — that self-correcting
loop is cheaper than manual verification.
**Don't introspect via `[System.Reflection]`** to enumerate Reactor types or
members — the skill files plus `mur check`'s did-you-mean suggestions plus
`skills/reactor.api.txt` cover the surface.
Workflow modes (Phase-2 ranker):
- `mur check` — iteration mode (default). A ranker suppresses cosmetic noise
(CS1591 XML doc, CS0168 unused-var, IDE0xxx style, NuGet restore chatter)
mid-iteration so the real blocker doesn't scroll off attention. **When this
exits 0, you are done** — the build is green.
- `mur check --final` — optional pre-merge sweep. Emits the cosmetic
diagnostics suppressed during iteration (XML doc, unused locals, style
hints, nullable warnings, transient restore noise). For human code review
or a CI ship-readiness gate; **not** a task-completion requirement and
skipping it is fine.
- `mur check -- <msbuild args>` — anything after a bare `--` is forwarded
verbatim to `dotnet build` (override platform, config, restore, verbosity).
## Sub-skills — load when the task calls for them
| Skill | When to load |
|---|---|
| [`skills/async.md`](skills/async.md) | Fetching data, caching, pagination, optimistic writes. `UseResource`, `UseMutation`, `UseInfiniteResource`, `Pending`. |
| [`skills/design.md`](skills/design.md) | Any visual-styling work. Windows 11 design rules — theme tokens, High Contrast, typography, 4px grid, acrylic surfaces, accessibility. |
| [`skills/commanding.md`](skills/commanding.md) | Actions that appear in multiple surfaces (menu + toolbar), need keyboard shortcuts, or need `CanExecute`. `Command`, `StandardCommand`, `UseCommand`, `CommandHost`. |
| [`skills/devtools.md`](skills/devtools.md) | Drive a running app via `mur devtools` — screenshot, inspect visual tree, click/type/scroll, read hook state. Load when diagnosing visible bugs (layout, contrast) or verifying a change landed. |
| [`skills/navigation.md`](skills/navigation.md) | Multi-page apps, sidebar/tab navigation, routes, deep linking, page transitions, caching. `UseNavigation`, `NavigationHost`, `NavigationView`, `TabView`. |
| [`skills/forms.md`](skills/forms.md) | Data-entry screens, validation, masked/formatted input. `UseValidationContext`, `FormField`, `MaskEngine`, `InputFormatter`. |
| [`skills/input.md`](skills/input.md) | Gestures, pointer events, drag-and-drop, focus management. `OnPan`, `OnPinch`, `OnRotate`, `OnDragStarting`, `UseElementFocus`. |
| [`skills/charts.md`](skills/charts.md) | Data visualization — choosing a chart type (incl. donut, `TreeChart`, `ForceGraph`), the chart DSL, the `LabelView` / `XTickLabelView` / `YTickLabelView` extension points for icon-plus-text and rich labels, plus the visualization-best-practices rules to refuse to break. |
| [`skills/dsl-reference.md`](skills/dsl-reference.md) | Look up signatures — every factory, modifier, and enum in the DSL. |
## Project Setup
### .csproj (copy exactly)
```xml
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net10.0-windows10.0.22621.0</TargetFramework>
<Platforms>x64;ARM64</Platforms>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<UseWinUI>true</UseWinUI>
<WindowsPackageType>None</WindowsPackageType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.UI.Reactor" Version="0.0.0-local" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="2.2.0" />
</ItemGroup>
</Project>
```
In selfhost the version is `0.0.0-local` (produced by `mur pack-local` —
see "Which mode are you in?" above). Outside the source clone, replace it
with whatever Microsoft.UI.Reactor version you depend on.
**After `dotnet new reactor -n <Name>`, the entry point is `App.cs`**
(entry point + initial component), next to `<Name>.csproj`. The template
also emits packaging scaffolding you normally don't touch:
`Package.appxmanifest`, `app.manifest`, `Assets/`, and
`Properties/launchSettings.json` + `Properties/PublishProfiles/`. There is no
`Program.cs` and no `GlobalUsings.cs` — modify `App.cs` in place. `App.cs` has
its own `using` directives at the top — the canonical set (System + Reactor +
Reactor.Core + Reactor.Layout + Xaml + Xaml.Controls + static
Factories) — which is the only place you add new namespaces (e.g. `using System.Linq;` when
you reach for `.Select(...)`). Don't probe the `.csproj` after
scaffolding unless you're adding a `PackageReference` or changing a
property — `Restore succeeded.` in the scaffold stdout is the only
confirmation you need.
Apps from `dotnet new reactor` are **packaged** (single-project MSIX), so
`dotnet run` launches them with package identity and needs Developer Mode on.
The other short names are `reactor-mvu`, `reactor-navview`, and
`reactor-tabview`.
**Verify your edits with `mur check`** before declaring done. From the
project directory: `mur check` (no arguments) runs `dotnet build` and
emits one compressed line per diagnostic with a `→ try:` suggestion
when the engine recognizes the mistake; `mur check --final` is the
explicit "I am done iterating" sweep that emits the full diagnostic
set including suppressed iteration-mode warnings. For anything more
involved than the build/fix loop — strict-mode failures, custom
diagnostic gating, MSBuild passthrough flags — load the
`reactor-build-and-check` skill.
### nuget.config (selfhost only — sibling of the .csproj)
If your .csproj lives **outside** the Reactor clone, add a `nuget.config`
next to it pointing at the clone's `local-nupkgs/` (absolute path):
```xml
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="reactor-local" value="C:\path\to\reactor2\local-nupkgs" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
</packageSources>
</configuration>
```
Inside the clone you don't need this — the repo-level `nuget.config`
already configures the feed.
For a **hand-authored** csproj like the one above, `WindowsPackageType` MUST be
`None` (unpackaged, no App.xaml) and `UseWinUI` MUST be `true`. Apps scaffolded
by `dotnet new reactor` are packaged instead and omit `WindowsPackageType`
entirely — leave their packaging properties alone. Either way: no XAML files of
any kind.
### Required imports
```csharp
using Microsoft.UI.Reactor;
using Microsoft.UI.Reactor.Core;
using Microsoft.UI.Reactor.Layout; // FlexDirection, FlexJustify, ... (if using Flex)
using Microsoft.UI.Xaml; // Thickness, HorizontalAlignment, VerticalAlignment
using Microsoft.UI.Xaml.Controls; // Orientation, InfoBarSeverity, etc.
using static Microsoft.UI.Reactor.Factories; // TextBlock(), Button(), VStack() bare calls
```
### App entry point
```csharp
// Component root
Ver no GitHub