agent.md
This file is the single source of truth for AI/agent assistance in this repository (Claude Code, GitHub Copilot, and other coding agents). It consolidates build/test commands, architecture context, coding standards, and AOT guidance.
If there is any conflict between other agent instruction files and this file, follow agent.md.
./srcsrc/reactiveui.slnxBenchmarks/ReactiveUI.Benchmarks.slnintegrationtests/ (platform-specific solutions; not required for most tasks)CRITICAL: Use a full, recursive clone. Shallow clones can fail because build/versioning relies on git history. If a clone has already been done you must use the unshallow commit command in git.
git clone --recursive https://github.com/reactiveui/reactiveui.git
This repository uses SLNX (XML-based solution format) instead of legacy .sln.
dotnet build/test the same way .sln doessrc/reactiveui.slnxCRITICAL: Platform workloads must be restored or the build will fail. Run from the ./src directory.
dotnet --info
cd src
dotnet workload restore
cd ..
CRITICAL: Run build/test commands from ./src unless the command explicitly uses src/-prefixed paths.
cd src
dotnet restore reactiveui.slnx
dotnet build reactiveui.slnx -c Release
dotnet build reactiveui.slnx -c Release -warnaserror
dotnet clean reactiveui.slnx
Building the full solution requires Windows due to Windows-only target frameworks (WPF, WinUI, .NET Framework). Non-Windows builds may fail; this is expected. In non-Windows environments, focus on documentation, targeted library changes, or analysis that does not require full compilation.
This repo uses Microsoft Testing Platform (MTP) with TUnit. This differs from VSTest.
global.jsontestconfig.jsonTestingPlatformDotnetTestSupport in Directory.Build.propsKey rule: TUnit/MTP arguments go after --.
--no-build. Always build before testing to avoid stale binaries.--output Detailed before --."parallel": false in testconfig.json) to avoid interference../src)cd src
# Run all tests
dotnet test --solution reactiveui.slnx -c Release
# Run tests for a specific project
dotnet test --project tests/ReactiveUI.Tests/ReactiveUI.Tests.csproj
# Run with code coverage (Microsoft Code Coverage)
dotnet test --solution reactiveui.slnx --coverage --coverage-output-format cobertura
# Detailed output (place BEFORE --)
dotnet test --solution reactiveui.slnx -- --output Detailed
dotnet test --solution reactiveui.slnx --coverage --coverage-output-format cobertura -- --report-trx --output Detailed
# List tests
dotnet test --project tests/ReactiveUI.Tests/ReactiveUI.Tests.csproj -- --list-tests
# Fail fast
dotnet test --solution reactiveui.slnx -- --fail-fast
# Limit parallelism if needed (even though repo defaults non-parallel)
dotnet test --solution reactiveui.slnx -- --maximum-parallel-tests 4
--treenode-filter SyntaxPattern: /{AssemblyName}/{Namespace}/{ClassName}/{TestMethodName}
Examples:
# Single test
dotnet test --project tests/ReactiveUI.Tests/ReactiveUI.Tests.csproj -- --treenode-filter "/*/*/*/MyTestMethod"
# All tests in class
dotnet test --project tests/ReactiveUI.Tests/ReactiveUI.Tests.csproj -- --treenode-filter "/*/*/MyClassName/*"
# All tests in namespace
dotnet test --project tests/ReactiveUI.Tests/ReactiveUI.Tests.csproj -- --treenode-filter "/*/MyNamespace/*/*"
# Filter by property (e.g., Category)
dotnet test --solution reactiveui.slnx -- --treenode-filter "/*/*/*/*[Category=Integration]"
See: https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-test?tabs=dotnet-test-with-mtp TUnit flags reference: https://tunit.dev/docs/reference/command-line-flags
src/global.json — sets "Microsoft.Testing.Platform" runnersrc/testconfig.json — test execution settings (parallel false, coverage format, etc.)src/Directory.Build.props — repository-wide build configuration (incl. TestingPlatformDotnetTestSupport).github/copilot-instructions.md — may exist, but should defer to this agent.mdReactiveUI is a cross-platform MVVM framework built on Rx.NET and functional reactive programming principles.
src/ReactiveUI/)ReactiveObject/ — reactive INotifyPropertyChanged baseReactiveCommand/ — observable command pipelinesActivation/ — view/viewmodel activation lifecycleBindings/ — one-way/two-way binding infrastructureExpression/ — expression tree analysis for observation (WhenAnyValue)Routing/ — navigation/routingInteractions/ — request/response patternsBuilder/ — DI and service registration patternsExamples:
ReactiveUI.Wpf/, ReactiveUI.WinUI/, ReactiveUI.Maui/, ReactiveUI.AndroidX/,
ReactiveUI.Blazor/, ReactiveUI.Winforms/, ReactiveUI.Testing/, etc.RxSchedulers (AOT-friendly, avoids reflection/AOT attribute propagation)RxApp only when required (e.g., unit test scheduler detection)See docs/RxSchedulers.md.
This repository targets net8.0+ and supports AOT/trimming scenarios.
Prefer strongly-typed and source-generator-friendly approaches. Avoid reflection-heavy patterns that require trimming/AOT attributes.
#if NET6_0_OR_GREATER guards). Polyfills are available.Example (only when truly needed):
private static object CreateInstance(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
Type type)
{
return Activator.CreateInstance(type)!;
}
If a warning cannot be resolved without harming design, use suppression attributes with a clear justification. Prefer minimal scope and specific suppression IDs.
CRITICAL: Follow ReactiveUI contribution guidelines: https://www.reactiveui.net/contribute/index.html
.editorconfig formatting/naming conventions_camelCase, readonly where possible, static readonly orderint, string) rather than BCL typesnameof() over string literalsthis. unless necessaryvar when it improves readabilityIf a specific file already follows a local style, adhere to existing file conventions.
No #pragma warning disable in production code.
[SuppressMessage] with clear justification.Example:
// WRONG
#pragma warning disable CA1062
public void MyMethod(object parameter)
{
parameter.ToString();
}
#pragma warning restore CA1062
// CORRECT
public void MyMethod(object parameter)
{
ArgumentNullException.ThrowIfNull(parameter);
parameter.ToString();
}
// LAST RESORT ONLY
[SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods",
Justification = "TUnit guarantees non-null parameters from data sources.")]
public async Task MyTest(IConverter converter, int expectedValue)
{
var result = converter.GetValue();
await Assert.That(result).IsEqualTo(expectedValue);
}
Use TUnit + Microsoft Testing Platform
Write unit tests for new features and bug fixes
Prefer existing patterns in:
src/tests/ReactiveUI.Tests/src/tests/ReactiveUI.AOTTests/Use ReactiveUI.Testing utilities for reactive code
public class SampleViewModel : ReactiveObject
{
private string? _name;
private readonly ObservableAsPropertyHelper<bool> _isValid;
public SampleViewModel()
{
_isValid = this.WhenAnyValue(x => x.Name)
.Select(name => !string.IsNullOrWhiteSpace(name))
.ToProperty(this, nameof(IsValid));
SubmitCommand = ReactiveCommand.CreateFromTask(
ExecuteSubmit,
this.WhenAnyValue(x => x.IsValid));
}
public string? Name
{
get => _name;
set => this.RaiseAndSetIfChanged(ref _name, value);
}
public bool IsValid => _isValid.Value;
public ReactiveCommand<Unit, Unit> SubmitCommand { get; }
private async Task ExecuteSubmit(CancellationToken cancellationToken)
{
// Implementation
}
}
public IObservable<string> GetData()
{
return Observable.Return("data")
.ObserveOn(RxSchedulers.MainThreadScheduler);
}
this.WhenAnyValue(
x => x.FirstName,
x => x.LastName,
(first, last) => $"{first} {last}")
.Subscribe(fullName => { /* handle */ });
this.WhenAnyValue(x => x.IsLoading)
.Where(isLoading => !isLoading)
.Subscribe(_ => { /* handle */ });
private readonly ObservableAsPropertyHelper<decimal> _total;
public decimal Total => _total.Value;
_total = this.WhenAnyValue(
x => x.Quantity,
x => x.Price,
(qty, price) => qty * price)
.ToProperty(this, nameof(Total));
src/ReactiveUI/ core library