Unilyze 0.7.0

dotnet tool install --global Unilyze --version 0.7.0
                    
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest
                    
if you are setting up this repo
dotnet tool install --local Unilyze --version 0.7.0
                    
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=Unilyze&version=0.7.0
                    
nuke :add-package Unilyze --version 0.7.0
                    

unilyze

CI Code Health NuGet Homebrew Scoop

C# static analysis that runs on .cs and .asmdef alone — no MSBuild or sln required. Computes churn × complexity hotspots from git history, live-updates metrics in the browser on save (unilyze serve), and ships a self-documenting CLI (metrics, schema, query) with bundled AI agent skills. General C# projects are supported via .csproj discovery and semantic analysis when a solution is present.

For build, test, and release information, see README.dev.md.

Demo

<div><video controls src="https://github.com/user-attachments/assets/60ae2566-f961-4324-a16d-8f384b7d03fd" muted="false"></video></div>

Type dependency graph with Code Health badges

Live demo (unilyze analyzing its own source): https://bigdra50.github.io/unilyze/demo/

Documentation: https://bigdra50.github.io/unilyze/

Requirements

  • No .NET installation is required for Homebrew, Scoop, or direct-download binaries
  • The dotnet tool channel requires .NET 8.0 or later

.NET version support policy: The dotnet tool channel targets every TFM from the oldest supported LTS up to the latest LTS, with no gaps. EOL is not an exclusion criterion; the floor LTS is raised only once it reaches EOL. As of 2026-06, supported TFMs are net8.0, net9.0, and net10.0.

Quick Start

For users who already have .NET, the global tool remains the recommended installation:

dotnet tool install --global Unilyze

Install a self-contained binary without .NET:

# macOS or Linux
brew install bigdra50/tap/unilyze

# Windows
scoop install https://github.com/bigdra50/unilyze/releases/latest/download/unilyze.json

Release archives for osx-arm64, osx-x64, linux-x64, and win-x64 are also available from GitHub Releases. Verify downloads with the attached SHA256SUMS file. For a macOS archive downloaded through a browser, remove the quarantine attribute before the first run:

xattr -d com.apple.quarantine ./unilyze

Run in a Unity project directory to open the analysis results in your browser:

cd ~/MyUnityProject
unilyze

Tutorials

Step-by-step walkthroughs for the highest-value workflows:

  • CI quality gate — badge gates, diff --fail-on-regression, PR markdown comments, --base-ref baselines
  • Agent integration — skills install, evidence packs (query), refactor-loop and quality-audit workflows
  • Continuous refactoring — hotspot prioritization, snapshot history, trend interpretation

Usage

unilyze                                          # Analyze and open in browser
unilyze -p ~/MyUnityProject                      # Specify project path
unilyze -p ~/MyUnityProject -o graph.html        # Save HTML + JSON
unilyze -p ~/MyUnityProject -f json -o result.json  # JSON output
unilyze -p ~/MyUnityProject -f sarif -o report.sarif # SARIF (stable fingerprints)
unilyze -p ~/MyUnityProject --profile unity      # Unity role-aware smell thresholds
unilyze -p ~/MyUnityProject --baseline .unilyze/baseline.json  # Suppress known smells
unilyze -p ~/MyUnityProject --level core         # Pin analysis level

Subcommands

unilyze config list                                # Show/manage configuration
unilyze baseline create -p .                       # Snapshot smells for zero-new-violations
unilyze diff <before.json> <after.json>            # Compare snapshots (JSON)
unilyze diff --base-ref origin/main after.json -f markdown --fail-on-regression
unilyze diff <before.json> <after.json> -o diff.html --changed-only
unilyze hotspot -p ~/MyUnityProject                # Git churn × complexity
unilyze dup -p ~/MyUnityProject                    # Token-normalized clone detection
unilyze trend <dir-of-jsons>                       # Quality trend across snapshots
unilyze trend <dir-of-jsons> -o trend.html         # Self-contained HTML trend charts
unilyze query --worst 5 -i snapshot.json           # Per-type evidence packs
unilyze calibrate <dir-of-jsons> -o thresholds.json  # Derive threshold candidates
unilyze statusline -p ~/MyUnityProject             # Compact summary for status line
unilyze badge -p ~/MyUnityProject -o badge.json    # shields.io endpoint JSON
unilyze metrics                                    # Metric definitions & thresholds
unilyze schema                                     # JSON field reference
unilyze skills install --claude --cursor           # Install agent skills

Run unilyze --help for all options. JSON output includes projectKind (unity | dotnet) and profile.

Exit codes (all commands): 0 success / gate passed, 1 usage error, 2 quality gate failed (badge with --fail-under / --fail-over, or diff with --fail-on-regression).

Status Line Integration

unilyze statusline outputs a one-line code health summary (e.g. CH:9.8/5.9 W:9.4 T:7.2 111smells 🔴1 📦66). Pass --show-mi to append the reference MI metric. It never blocks: the cached line prints immediately while a stale or missing cache refreshes in the background, so it is safe for Claude Code's status bar. Details: docs/statusline.md.

Badges

unilyze badge -p . --metric codehealth --fail-under 7   # CI gate example
unilyze badge -p . --metric energy --fail-over 1.0      # Unity hot-path smell density proxy
unilyze badge -p . --format svg -o .github/badges/codehealth.svg

The energy metric is a static source-code proxy, not measured energy or power.

See the CI quality gate tutorial and docs/ci-integration.md for endpoint vs SVG badges, quality-gate semantics, GitHub Actions, diff regression gates, and monorepo --projects batch analysis.

Private repositories

Generate SVG with unilyze badge --format svg, commit under .github/badges/, and reference via a relative path — shields.io endpoints do not work in private repos. See docs/ci-integration.md#private-repositories.

GitHub Action

- uses: bigdra50/unilyze@v1
  with:
    project-path: .
    metric: codehealth
    fail-under: "7.0"
    base-ref: origin/main
    fail-on-regression: "true"
    baseline: .unilyze/baseline.json

Full workflow YAML, input table, and badges.yml publishing pattern: docs/ci-integration.md.

Why unilyze

unilyze NDepend SonarQube CodeScene Qodana
Unity setup .cs/.asmdef alone, Unity DLLs resolved progressively VS solution / compiled assemblies required MSBuild project required (SonarScanner for .NET) Git repo + service onboarding; no Unity-specific analysis .sln/.csproj pre-generated (Rider sync script)
Churn × complexity hotspots unilyze hotspot; method-level via --methods None (trend baselines only) None ("Security Hotspot" is unrelated) File-level; function-level in X-Ray None
Agent integration Bundled skills (Claude/Codex/Cursor/Gemini/Windsurf), self-documenting CLI (metrics/schema/query), stable JSON NDepend MCP SonarQube MCP Server CodeScene MCP None found in survey

Analysis Levels

unilyze resolves an analysis level based on which Unity DLLs it can locate. Pin with --level <syntax|core|full|complete>. See docs/ci-integration.md#analysis-levels-in-ci for the full table and CI caveats.

Incremental analysis

--incremental caches per-type analysis results under <project>/.unilyze/cache/syntax/v1/ and works at every analysis level. Warm syntax-level runs re-parse only changed files. Warm semantic runs (core/full/complete) additionally reuse per-type enrichment (LCOM/CBO/DIT/RFC + code smells) with reverse-dependency-index (RDI) invalidation: a body-only edit re-enriches just the edited types; a signature, using-directive, member, or base/interface-list change re-enriches the changed types plus their recorded dependents (and inheritance descendants where bindings can shift); type or file adds/deletes and global-using changes conservatively re-enrich everything. Cross-file aggregates (dependencies, coupling, cycles, rank) are always recomputed in full, so warm output is byte-identical to a full run.

unilyze -p . --incremental -f json -o result.json   # any analysis level

Requirements and limits:

  • Cannot be used with -i/--input.
  • Cache invalidates when toolVersion, metricsVersion, preprocessor defines, thresholds/profile/rules, exclude dirs, assembly layout, resolved references, target framework, or analysis level change.
  • CI: persist .unilyze/cache/ with actions/cache keyed on lockfiles and .unilyze.json to reuse warm analysis across runs.

The cache directory includes .unilyze/cache/.gitignore containing * (auto-created).

unilyze serve always analyzes at the semantic level with the incremental cache warm; pass serve --verify-incremental <N> to additionally run a full analysis every N generations and log any divergence to stderr (off by default — it doubles analysis cost on the sampled generations).

Configuration

Settings merge additively from global config (~/.config/unilyze/config.json), project .unilyze.json, and CLI flags.

Scope Path
Global $XDG_CONFIG_HOME/unilyze/config.json
Project <project-root>/.unilyze.json
CLI --exclude-dir <dir> (repeatable)
// .unilyze.json
{
  "excludeDirs": ["Assets/Plugins", "Assets/ThirdParty"],
  "profile": "unity",
  "smells": { "LongMethod": { "lines": 100, "criticalLines": 200 } },
  "rules": { "UNI011": "off", "UNI009": "off" }
}

UNI009 off disables cyclic-dependency detection entirely. Other rule IDs map to smell kinds and filter JSON, SARIF, badge, and statusline output. Threshold keys are case-insensitive; defaults are in docs/metrics.md (drift-tested) and unilyze metrics.

Reference analysis opt-ins (.NET)

For general .NET projects, semantic metrics (CBO, DIT, boxing) use BCL references by default. Optional flags deepen resolution without MSBuild:

unilyze -p . --resolve-nuget              # NuGet compile assemblies from obj/project.assets.json (after dotnet restore)
unilyze -p . --include-generated        # EmitCompilerGeneratedFiles output (compilation only; metrics unchanged)
unilyze -p . --resolve-nuget --tfm net8.0 # Pin target framework for multi-TFM repos

Equivalent .unilyze.json keys: "resolveNuget", "includeGenerated", "targetFramework". Enabled settings are echoed in JSON output. Compare snapshots only with identical opt-in settings — see docs/metrics.md.

Suppressing findings

Three suppression mechanisms compose without double-counting:

Mechanism Scope When to use
Inline comment Single occurrence Justified one-off (intentional facade, measured-safe boxing site)
"rules": { "UNI011": "off" } Rule-wide Rule is noisy for the whole project
--baseline / baseline create Project snapshot Brownfield freeze; gate on new violations only

Inline directives (ESLint-style):

// unilyze-disable-next-line UNI014 -- top-level guard, intentional
catch { }

// unilyze-disable UNI002
void MeasuredLongMethod() { /* ... */ }
  • unilyze-disable-next-line suppresses listed rules on the following line (detector smells with line numbers).
  • unilyze-disable in the leading trivia of a type or method declaration suppresses listed rules for that declaration's scope.
  • Omit rule IDs to suppress all rules in scope. Unknown rule IDs and UNI009 print a stderr warning and are ignored.
  • Suppressed smells stay in JSON with "suppressed": true, increment root suppressedCount, and appear in SARIF with suppressions { "kind": "inSource" }. They are excluded from statusline, badge gates, and diff regression counts.

Known constraints: metric-based smells (UNI001–UNI008, UNI010) match directives by method or type name, so a directive on one overload suppresses the smell for all same-name overloads; detector smells (UNI011–UNI025) use line positions and distinguish overloads. For partial types, place type-scope directives on the declaration indexed by unilyze (see docs/metrics.md). UNI009 (cyclic dependency) is config-only.

Assembly mapping

Project kind Discovery One assembly per
Unity .asmdef under Assets/ asmdef name
.NET .csproj (solution-first, else recursive) csproj file name
Fallback no asmdef / no csproj single Assembly-CSharp

ProjectReference items become assembly dependency edges. --prefix and --assembly filter assemblies the same way for asmdefs and csproj-derived names.

unilyze config add-exclude-dir Assets/Plugins
unilyze baseline create -p . -o .unilyze/baseline.json

Metrics

Metric Description Granularity
Cognitive Complexity SonarSource-compliant cognitive complexity Method
Cyclomatic Complexity McCabe 1976-compliant cyclomatic complexity Method
Halstead D/E/B Difficulty, Effort, EstimatedBugs Method
LCOM-HS Henderson-Sellers cohesion Type
WMC Weighted Methods per Class Type
NOC / RFC / CBO / DIT Chidamber-Kemerer suite Type
Ca / Ce / Instability Martin package metrics Type
Maintainability Index Halstead Volume + CycCC + LoC Method
TypeRank PageRank-based importance Type
Code Health Composite score (1.0 worst – 10.0 best) Type
Abstractness / DfMS / Relational Cohesion Assembly-level metrics Assembly
Burst coverage / ECS type count [BurstCompile] adoption on ECS systems/jobs Assembly

Run unilyze metrics for definitions and thresholds. See docs/metrics.md for specifications and validation data.

Detection capabilities

Metric-threshold smells (God Class, Long Method, coupling, cohesion, etc.), performance analysis (boxing, closures, params arrays), exception-flow patterns, Unity frame-rate rules (UNI017–UNI021: hot-path API/LINQ/allocation/string concat, weak temporization), async/blocking rules (UNI022–UNI023), DOTS/ECS rules (UNI024–UNI025: missing [BurstCompile], managed IComponentData fields) with per-assembly burstCoverage, and DI container edge detection (VContainer, Zenject) — all configurable via .unilyze.json and --profile unity. Does not duplicate com.unity.entities source-generator diagnostics that fail the Editor build; see docs/metrics.md#dots--ecs. Thresholds are not duplicated here; see docs/metrics.md and unilyze metrics.

Output Formats

Format Use Case
html Interactive dependency graph (lazy Cytoscape elements; dagre bundled; ELK Worker via CDN)
json Agent integration, programmatic use
sarif GitHub Code Scanning (stable fingerprints, rule help links)

In-browser read-only source viewer

Diff Viewer

unilyze diff <before.json> <after.json> -o diff.html overlays metric deltas on the standard viewer (change badges, Changed only toggle, graph halos). Regression gates, markdown PR output, and --base-ref workflows: docs/ci-integration.md.

Diff viewer with degradation halos and metric badges

unilyze diff before.json after.json --fail-on-regression
unilyze diff --base-ref origin/main after.json -f markdown --changed-only

Agent Workflow

See the agent integration tutorial.

unilyze (measure) → unilyze query (evidence) → fix → unilyze diff (verify)
unilyze query --worst 5 -i snapshot.json          # evidence packs (md or -f json)
unilyze calibrate snapshots/ -o calibration.json  # percentile thresholds for .unilyze.json
unilyze skills install --claude --codex --cursor
unilyze metrics && unilyze schema                 # self-documenting CLI

Known Limitations

  • HTML graph works offline (Cytoscape and dagre bundled). ELK layout runs in a CDN-loaded Worker, falls back to main-thread ELK if Worker startup fails, and uses dagre when ELK is unavailable.
  • Large graphs initially materialize only namespace nodes and types in the initially expanded namespace. Type nodes and edges are added on expansion and removed on collapse.
  • Windows is covered by CI (windows-latest, net10.0).

License

MIT

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

Version Downloads Last Updated
0.7.0 50 10/23/2026
0.6.1 331 7/30/2026
0.6.0 145 7/7/2026
0.5.3 158 6/16/2026
0.5.2 147 6/15/2026
0.5.1 132 6/14/2026
0.5.0 131 6/14/2026
0.4.1 140 6/13/2026
0.4.0 127 6/13/2026
0.3.0 138 6/8/2026
0.2.2 136 5/19/2026
0.2.1 168 3/27/2026
0.2.0 147 3/22/2026
0.1.9 155 3/17/2026
0.1.8 131 3/15/2026
0.1.7 136 3/15/2026
0.1.6 123 3/15/2026
0.1.5 131 3/15/2026
0.1.4 129 3/15/2026
0.1.3 132 3/15/2026
Loading failed