anyscan 0.2.6
dotnet tool install --global anyscan --version 0.2.6
dotnet new tool-manifest
dotnet tool install --local anyscan --version 0.2.6
#tool dotnet:?package=anyscan&version=0.2.6
nuke :add-package anyscan --version 0.2.6
anyscan
Scans a .NET solution and reports architecture, API, performance, security, and C# naming findings.
Same engine, two ways in: CLI (anyscan scan) or MCP (anyscan mcp in Cursor). Pick one; you do not need both.
Install
dotnet tool install -g anyscan
Update:
dotnet tool update -g anyscan
Requires .NET 10.
If the machine has more than one NuGet source (a company feed, Nexus, a local folder), dotnet tool may resolve a different or incomplete anyscan package and fail with DotnetToolSettings.xml was not found in the package. Pin nuget.org and ignore the other feeds:
dotnet tool install -g anyscan --add-source https://api.nuget.org/v3/index.json --ignore-failed-sources
The same flags work on dotnet tool update. Add --version <x.y.z> to pin a published version.
On zsh (the default macOS shell) two extra problems show up:
- The .NET installer often writes
~/.dotnet/toolsinto.bashrc/.profile, not~/.zshrc. Ifanyscanis installed but the command is not found, add this to~/.zshrcand open a new terminal:
export PATH="$PATH:$HOME/.dotnet/tools"
- zsh caches command locations. After install, update, or a manual delete of the shim, run
rehash(orhash -r) in the current session. Otherwise zsh keeps looking at a removedanyscanbinary.
CLI
Terminal, CI, scripts:
anyscan scan ./MyApp.sln
anyscan scan ./MyApp.sln --depth surface
anyscan scan ./MyApp.sln --depth deep
anyscan scan ./MyApp.sln --format json --output report.json
anyscan scan ./MyApp.sln --format sarif --output report.sarif
anyscan scan ./MyApp.sln --fail-on warning
anyscan scan ./MyApp.sln --include-tests
anyscan scan ./MyApp.sln --with-dotnet-analyzers
--depth picks how much to run. It is separate from the architecture profile (EnterpriseApi / VerticalSlice):
| Depth | What runs |
|---|---|
surface (quick) |
File/project scanners only: secrets, production config, layer/BFF references, CORS, health. Skips Roslyn and the architecture graph. |
standard (default) |
Surface plus Roslyn and the architecture graph. |
deep (full) |
Standard plus --include-tests and --with-dotnet-analyzers. |
The summary and JSON report include the depth that actually ran. Do not compare a surface finding count to a deep one. --include-tests still works on every depth. --with-dotnet-analyzers has no effect on surface.
The command prints an ANY banner, then a summary of errors, warnings, and rule counts. Each rule lists the class and line (YFCoreService:83) so you can jump without opening the JSON. Config findings use the file name (appsettings.Prod.json:1). The JSON report includes typeName, location, filePath, and startLine. In a terminal it asks before writing anyscan-report.json. Answer y to export. --output writes that file without asking.
--format is text (default), json, or sarif. Progress is printed to stderr, so it does not mix with a piped JSON report.
By default the command exits with code 1 when a finding has severity error. --fail-on warning also fails on warnings. --fail-on none always exits 0 unless the scan itself fails.
SEC001, SEC003, and CONF011 skip test projects by default to cut noise. A path is treated as a test project when any /- or .-separated segment is test/tests (any case) or ends with the PascalCase word Test/Tests (UnitTests, IntegrationTests, E2ETests, SmokeTest). A coincidental lowercase stem (Contests, Latest) is not excluded. Pass --include-tests (or set "includeTests": true in anyarchitecture.json) for a full scan, e.g. as an optional CI job, since real credentials can end up in test code by accident too. Findings never include the real secret value — only the file, line, rule, and a fixed-length masked evidence string.
--with-dotnet-analyzers (or "includeDotnetAnalyzers": true) also runs the target solution's own configured .NET/CA analyzers (CA rules, StyleCop, etc.) through the same scan, in addition to anyscan's own rules. This switches to the slower MSBuild load mode and requires the solution to restore, so it is opt-in.
MCP
Same scan, from Cursor or another MCP client. Add to ~/.cursor/mcp.json or the project .cursor/mcp.json:
{
"mcpServers": {
"anyscan": {
"command": "anyscan",
"args": ["mcp"]
}
}
}
While developing this repo, point at the project instead:
{
"mcpServers": {
"anyscan": {
"command": "dotnet",
"args": ["run", "--project", "src/Any.Architecture.Scanner", "--", "mcp"]
}
}
}
Tools: scan (path, depth, optional rule/severity), list_rules, explain_rule. Depth, rule ids, and findings match the CLI. The scan tool does not run the target app and does not return secret values.
Configuration
anyscan looks for anyarchitecture.json in the solution directory and its parents. Without that file the profile is EnterpriseApi.
{
"architecture": "CleanArchitecture",
"profile": "EnterpriseApi",
"rules": {
"ARCH002": "error",
"NAME001": "warning"
},
"modules": {
"Orders": { "forbid": ["Billing"] }
},
"authorizationAttributes": ["ApiKey"],
"includeTests": false
}
Profiles: MinimalApi, EnterpriseApi, VerticalSlice.
Layer checks read Domain, Application, Infrastructure, and Api from project names. The VerticalSlice profile uses Features for the application layer.
Rules
- ARCH001–ARCH011 — controller data access and complexity, layer references, project and namespace cycles, domain isolation, infrastructure leakage, singleton/scoped lifetime, module boundaries, circular module dependency
- API001–API004, API010, API011 — response metadata, authorization (per-action attribute, global ASP.NET Core middleware, or a custom attribute listed in
authorizationAttributes), request validation, API versioning, missing cancellation token on an endpoint, possible missing pagination - PERF001–PERF008, PERF010, PERF011 — performance (including quadratic
Any/Contains/Firstinside a loop), EF Core tracking on read-only queries,DateTime.Now/UtcNowtestability - SEC001–SEC003, SEC010–SEC012 — hardcoded secrets, plaintext secrets in configuration and environment files, permissive CORS, disabled JWT validation, TLS certificate validation bypass, SQL built from string concatenation
- OBS001, OBS002, OBS010 — logging, missing trace/correlation context
- CONF001, CONF010, CONF011 — options validation, debug settings left in a production configuration file, placeholder/weak default secret left in a production configuration file
- RES001–RES003, RES010 — HTTP resilience, cancellation tokens, health checks, unbounded or aggressive retry policy
- NAME001–NAME006 — C# naming:
Iprefix, PascalCase, camelCase,_camelCasefields,Asyncsuffix. Also covered, in a complementary way, by naming-style rules in the repo's.editorconfig(plain naming-styles can't express every case these analyzers check, such as the test-method underscore exception). - BFF001–BFF003 — a project whose name or declared namespace has a
Bffsegment (Orders.Bff.ApiorOrders_BFF.Application): referencing Domain/Infrastructure directly (BFF001), owning a database package or connection type (BFF002), awaiting downstream calls sequentially instead of withTask.WhenAll(BFF003)
CONF010 and CONF011 treat a configuration file as production when a dot-separated name segment is Production or the common abbreviation Prod (appsettings.Production.json, appsettings.Prod.json). PreProd is a different environment and is not treated as production.
The report is an architecture compliance scan. It is not a production-readiness certificate.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.