diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml
index af22591..583716d 100644
--- a/.forgejo/workflows/ci.yml
+++ b/.forgejo/workflows/ci.yml
@@ -73,4 +73,4 @@ jobs:
feed="${{ forgejo.server_url }}/api/packages/${{ forgejo.repository_owner }}/nuget/index.json"
dotnet nuget add source --name forgejo --username forgejo-publish --password "$token" --store-password-in-clear-text "$feed"
- dotnet nuget push "artifacts/package/release/*.nupkg" --source forgejo --skip-duplicate
+ dotnet nuget push "artifacts/package/release/*.nupkg" "artifacts/package/release/*.snupkg" --source forgejo --skip-duplicate
diff --git a/src/sdk/Sdk/Geekeey.Arcade.NET.Sdk.Razor/PACKAGE.md b/src/sdk/Sdk/Geekeey.Arcade.NET.Sdk.Razor/PACKAGE.md
new file mode 100644
index 0000000..f3d0cc5
--- /dev/null
+++ b/src/sdk/Sdk/Geekeey.Arcade.NET.Sdk.Razor/PACKAGE.md
@@ -0,0 +1,29 @@
+# Geekeey.Arcade.NET.Sdk.Razor
+
+Opinionated MSBuild SDK for Razor class library and Blazor projects with standardized build, analyzer, and editor configuration defaults.
+
+## Getting started
+
+```xml
+
+
+ net8.0
+
+
+```
+
+## What it provides
+
+- Everything from the base `Geekeey.Arcade.NET.Sdk` (language, analyzer, editor, and packaging defaults), layered on top of the `Microsoft.NET.Sdk.Razor` SDK.
+- Opinionated `.editorconfig` settings for Razor projects, applied automatically via `EditorConfigFiles` (including file-based programs when `FileBasedProgram=true`).
+
+## Opt-outs
+
+| Property | Effect |
+| --- | --- |
+| `EnableDefaultJsonSerializationOptions=false` | Skips the `System.Text.Json` nullable annotation defaults. |
+| `IncludeDefaultBannedSymbols=false` | Skips the built-in `BannedSymbols.txt`. |
+| `BannedNewtonsoftJsonSymbols=false` | Skips the built-in `BannedSymbols.NewtonsoftJson.txt`. |
+| `SearchReadmeFileAbove=true` | Also searches parent directories for a `PACKAGE.md` to pack. |
+
+See the [repository](https://code.geekeey.de/geekeey/arcade) for the full configuration.
diff --git a/src/sdk/Sdk/Geekeey.Arcade.NET.Sdk.Test/PACKAGE.md b/src/sdk/Sdk/Geekeey.Arcade.NET.Sdk.Test/PACKAGE.md
new file mode 100644
index 0000000..4876a6c
--- /dev/null
+++ b/src/sdk/Sdk/Geekeey.Arcade.NET.Sdk.Test/PACKAGE.md
@@ -0,0 +1,33 @@
+# Geekeey.Arcade.NET.Sdk.Test
+
+Opinionated MSBuild SDK for test projects with standardized build, analyzer, and editor configuration defaults.
+
+## Getting started
+
+```xml
+
+
+ net8.0
+
+
+```
+
+## What it provides
+
+- Everything from the base `Geekeey.Arcade.NET.Sdk` (language, analyzer, editor, and packaging defaults), layered on top of the `Microsoft.NET.Sdk` SDK.
+- Marks consuming projects as test projects by setting `IsTestProject=true` automatically.
+- `Microsoft.Testing.Platform.MSBuild` integration out of the box.
+- Test result defaults that follow the artifacts layout: when `ArtifactsPath` is set, `TestResultsDirectory` defaults to `/testresults/` and the Microsoft.Testing.Platform `results-directory` option defaults accordingly. Any `TestingPlatformCommandLineOptionDefault` you define yourself is left untouched. Opt out by setting `TestResultsDirectory` yourself.
+- Generated `.testconfig.json` defaults with the results directory when the project does not own a `testconfig.json`. A consumer-owned `testconfig.json` wins and is not modified.
+- Opinionated `.editorconfig` settings for test projects, applied automatically via `EditorConfigFiles` (including file-based programs when `FileBasedProgram=true`).
+
+## Opt-outs
+
+| Property | Effect |
+| --- | --- |
+| `EnableDefaultJsonSerializationOptions=false` | Skips the `System.Text.Json` nullable annotation defaults. |
+| `IncludeDefaultBannedSymbols=false` | Skips the built-in `BannedSymbols.txt`. |
+| `BannedNewtonsoftJsonSymbols=false` | Skips the built-in `BannedSymbols.NewtonsoftJson.txt`. |
+| `SearchReadmeFileAbove=true` | Also searches parent directories for a `PACKAGE.md` to pack. |
+
+See the [repository](https://code.geekeey.de/geekeey/arcade) for the full configuration.
diff --git a/src/sdk/Sdk/Geekeey.Arcade.NET.Sdk.Test/Sdk.props b/src/sdk/Sdk/Geekeey.Arcade.NET.Sdk.Test/Sdk.props
index 6683f9f..7c6b9dd 100644
--- a/src/sdk/Sdk/Geekeey.Arcade.NET.Sdk.Test/Sdk.props
+++ b/src/sdk/Sdk/Geekeey.Arcade.NET.Sdk.Test/Sdk.props
@@ -1,5 +1,6 @@
+ true
<_MustImportMicrosoftNETSdk Condition="'$(UsingMicrosoftNETSdk)' != 'true'">true
$(CustomBeforeDirectoryBuildProps);$(MSBuildThisFileDirectory)../common/Common.props
diff --git a/src/sdk/Sdk/Geekeey.Arcade.NET.Sdk.Web/PACKAGE.md b/src/sdk/Sdk/Geekeey.Arcade.NET.Sdk.Web/PACKAGE.md
new file mode 100644
index 0000000..dae948b
--- /dev/null
+++ b/src/sdk/Sdk/Geekeey.Arcade.NET.Sdk.Web/PACKAGE.md
@@ -0,0 +1,29 @@
+# Geekeey.Arcade.NET.Sdk.Web
+
+Opinionated MSBuild SDK for ASP.NET Core web projects with standardized build, analyzer, and editor configuration defaults.
+
+## Getting started
+
+```xml
+
+
+ net8.0
+
+
+```
+
+## What it provides
+
+- Everything from the base `Geekeey.Arcade.NET.Sdk` (language, analyzer, editor, and packaging defaults), layered on top of the `Microsoft.NET.Sdk.Web` SDK.
+- Opinionated `.editorconfig` settings for web projects, applied automatically via `EditorConfigFiles` (including file-based programs when `FileBasedProgram=true`).
+
+## Opt-outs
+
+| Property | Effect |
+| --- | --- |
+| `EnableDefaultJsonSerializationOptions=false` | Skips the `System.Text.Json` nullable annotation defaults. |
+| `IncludeDefaultBannedSymbols=false` | Skips the built-in `BannedSymbols.txt`. |
+| `BannedNewtonsoftJsonSymbols=false` | Skips the built-in `BannedSymbols.NewtonsoftJson.txt`. |
+| `SearchReadmeFileAbove=true` | Also searches parent directories for a `PACKAGE.md` to pack. |
+
+See the [repository](https://code.geekeey.de/geekeey/arcade) for the full configuration.
diff --git a/src/sdk/Sdk/Geekeey.Arcade.NET.Sdk/PACKAGE.md b/src/sdk/Sdk/Geekeey.Arcade.NET.Sdk/PACKAGE.md
new file mode 100644
index 0000000..106afff
--- /dev/null
+++ b/src/sdk/Sdk/Geekeey.Arcade.NET.Sdk/PACKAGE.md
@@ -0,0 +1,33 @@
+# Geekeey.Arcade.NET.Sdk
+
+Opinionated MSBuild SDK for .NET projects with standardized build, analyzer, and editor configuration defaults.
+
+## Getting started
+
+```xml
+
+
+ net8.0
+
+
+```
+
+## What it provides
+
+- Sensible language defaults: `ImplicitUsings` and `Nullable` enabled, extra global usings for `System.Diagnostics.CodeAnalysis`, `System.Globalization`, and `System.Text`.
+- Code quality defaults: `AnalysisLevel=latest`, `AnalysisMode=Recommended`, `EnforceCodeStyleInBuild`, nullable warnings as errors, and all warnings as errors on CI (`ContinuousIntegrationBuild`).
+- Opinionated `.editorconfig` settings, applied via `EditorConfigFiles` (including file-based programs when `FileBasedProgram=true`).
+- Banned API analysis with `Microsoft.CodeAnalysis.BannedApiAnalyzers` (with a built-in `BannedSymbols.txt`), public API analysis with `Microsoft.CodeAnalysis.PublicApiAnalyzers`, and RESX source generation with `Microsoft.CodeAnalysis.ResxSourceGenerator`.
+- `System.Text.Json` defaults that honor nullable annotations and `required` constructor parameters. Opt out with `EnableDefaultJsonSerializationOptions=false`.
+- NuGet packaging metadata defaults: `Authors`, `Copyright`, `PublishRepositoryUrl`, symbol packages (`snupkg`), and automatic packaging of a `PACKAGE.md` readme, `THIRD-PARTY-NOTICES` file, and a detected license file.
+
+## Opt-outs
+
+| Property | Effect |
+| --- | --- |
+| `EnableDefaultJsonSerializationOptions=false` | Skips the `System.Text.Json` nullable annotation defaults. |
+| `IncludeDefaultBannedSymbols=false` | Skips the built-in `BannedSymbols.txt`. |
+| `BannedNewtonsoftJsonSymbols=false` | Skips the built-in `BannedSymbols.NewtonsoftJson.txt`. |
+| `SearchReadmeFileAbove=true` | Also searches parent directories for a `PACKAGE.md` to pack. |
+
+See the [repository](https://code.geekeey.de/geekeey/arcade) for the full configuration.
diff --git a/src/sdk/configuration/Geekeey.CodingStyle.editorconfig b/src/sdk/configuration/Geekeey.CodingStyle.editorconfig
index f204a1b..1722fef 100644
--- a/src/sdk/configuration/Geekeey.CodingStyle.editorconfig
+++ b/src/sdk/configuration/Geekeey.CodingStyle.editorconfig
@@ -218,7 +218,7 @@ dotnet_style_prefer_compound_assignment = true
# Remove unnecessary expression value (IDE0058)
# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0058
-dotnet_diagnostic.IDE0058.severity = warning
+dotnet_diagnostic.IDE0058.severity = none
csharp_style_unused_value_expression_statement_preference = discard_variable
# Remove unnecessary value assignment (IDE0059)