diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
index dc057a1e03e..906ab863b91 100644
--- a/.github/copilot-instructions.md
+++ b/.github/copilot-instructions.md
@@ -7,6 +7,7 @@
- `src/Xamarin.Android.Build.Tasks/` - MSBuild tasks for Android apps
- `src/native/` - Native runtime (MonoVM/CoreCLR/NativeAOT)
- `external/Java.Interop/` - JNI bindings and Java-to-.NET interop
+- `external/xamarin-android-tools/` - Shared SDK tooling: `AndroidTask`/`AsyncTask` base classes, `AdbRunner`, `EmulatorRunner`, NRT extensions (`IsNullOrEmpty()`, `IsNullOrWhiteSpace()`), `CreateTaskLogger`, and SDK info utilities
- `tests/` - NUnit tests, integration tests, device tests
**Build System:** MSBuild + .NET Arcade SDK + CMake (native)
@@ -32,7 +33,7 @@ Reference official Android documentation where helpful:
**Use Microsoft docs:** Search MS Learn before making .NET, Windows, or Microsoft features, APIs, or integrations. Use the `microsoft_docs_search` tool.
-**MSBuild Tasks:** Extend `AndroidTask` base class, use `XA####` error codes, test in isolation.
+**MSBuild Tasks:** Extend `AndroidTask` base class, use `XA####` error codes, test in isolation. Use `AsyncTask` for tasks that need `async`/`await` — it handles `Yield()`, `try`/`finally`, and `Reacquire()` automatically.
**Internal build `` elements:** For `xa-prep-tasks` and `BootstrapTasks` (internal build-time tasks, not shipped to customers), always use `TaskFactory="TaskHostFactory"` and `Runtime="NET"` attributes on `` elements. This runs the task in a separate process to avoid Windows file locking issues and ensures the task runs on .NET (even when MSBuild.exe in Visual Studio uses .NET Framework). Example:
@@ -57,6 +58,10 @@ When opting C# code into nullable reference types:
* Don't *ever* use `!` (null-forgiving operator) to handle `null`! Always check for null explicitly and throw appropriate exceptions.
+* **In test code**, avoid `!` too. Common workarounds:
+ - `[SetUp]`-initialized fields: declare as nullable (`MockBuildEngine? engine;`) instead of `MockBuildEngine engine = null!;`
+ - After `Assert.IsNotNull`: extract into a local variable (`var opts = task.Options; Assert.IsNotNull (opts); opts.Foo...`) instead of using `task.Options!.Foo`
+
* Declare variables non-nullable, and check for `null` at entry points.
* Use `throw new ArgumentNullException (nameof (parameter))` in `netstandard2.0` projects.
@@ -181,7 +186,9 @@ This pattern ensures proper encoding, timestamps, and file attributes are handle
## Error Patterns
- **MSBuild Errors:** `XA####` (errors), `XA####` (warnings), `APT####` (Android tools)
-- **Logging:** Use `Log.LogError`, `Log.LogWarning` with error codes and context
+- **Error messages:** Must come from `Properties.Resources` (e.g., `Properties.Resources.XA0143`) for localization support. Add new messages to the English `Resources.resx` file.
+- **Error code lifecycle:** When removing functionality that used an `XA####` code, either repurpose the code or remove it from `Resources.resx` and `Resources.Designer.cs`. Don't leave orphaned codes.
+- **Logging in `AsyncTask`:** Use the thread-safe helpers (`LogCodedError()`, `LogMessage()`, `LogCodedWarning()`, `LogDebugMessage()`) instead of `Log.*`. The `Log` property is marked `[Obsolete]` on `AsyncTask` because calling `Log.LogMessage` directly from a background thread can hang Visual Studio.
## Troubleshooting
- **Build:** Clean `bin/`+`obj/`, check Android SDK/NDK, `make clean`