Graphify.CSharp 0.1.5

There is a newer version of this package available.
See the version list below for details.
dotnet tool install --global Graphify.CSharp --version 0.1.5
                    
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 Graphify.CSharp --version 0.1.5
                    
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=Graphify.CSharp&version=0.1.5
                    
nuke :add-package Graphify.CSharp --version 0.1.5
                    

Graphify C#

CI NuGet NuGet downloads License: MIT

A headless Roslyn/MSBuild semantic enricher for Graphify.

It emits deterministic C# declaration nodes, directed Roslyn-resolved semantic relationships, provenance, and stable source locations in Graphify’s JSON shape. Downstream Graphify queries can use the edges and namespace metadata to answer repository-specific questions such as caller and zero-inbound-reference audits.

Quick start

Run from a repository containing the solution, project, or file-based app you want to inspect:

dotnet tool install --global Graphify.CSharp --framework net10.0
graphify-csharp \
  --input ./src/MyProduct.sln \
  --root . \
  --configuration Release \
  --output ./graphify-out/csharp.json

The package contains one tool asset for each supported .NET runtime. Use the net10.0 asset for the normal C# 14 path. For a project using C# 15 syntax, install or update the same package with --framework net11.0; that asset uses the .NET 11 Roslyn compiler surface:

dotnet tool update --global Graphify.CSharp --framework net11.0

The install/update --framework selects the tool runtime. The command’s --target-framework option selects the analyzed project compilation and is still only needed when that project is multi-targeted or when a particular target must be inspected.

One-shot runs keep the complete Graphify JSON public output while reusing a validated internal project-contribution cache when inputs are unchanged. Use --rebuild to invalidate that cache and extract every project again.

For repeated work in a repository, keep one warm watcher process running:

graphify-csharp \
  --input ./src/MyProduct.sln \
  --root . \
  --configuration Release \
  --output ./graphify-out/csharp.json \
  --watch

The watcher keeps Roslyn state in memory, queues file-system hints, performs background indexing, and does not rewrite JSON for ordinary file changes. A normal invocation in another shell connects only when the analysis settings and exact output path match, then waits for the complete JSON publication barrier. If no matching watcher is running—including when another watcher uses the same project with a different output path—it falls back to a cold one-shot refresh:

graphify-csharp \
  --input ./src/MyProduct.sln \
  --root . \
  --configuration Release \
  --output ./graphify-out/csharp.json

Use --rebuild on that foreground command to force a full cache-invalidating rebuild. The watcher’s independent backup inventory scan defaults to five minutes and can be changed when starting it with, for example, --watch-scan-interval 00:02:00. Watcher errors, queue overflow, missing roots, and failed inventory scans recreate the watcher and complete a cold rebuild before serving the next request. No user files are removed during recovery.

An SDK file-based app can be passed directly when there is no .csproj yet:

graphify-csharp \
  --input ./src/App.cs \
  --root . \
  --configuration Release \
  --output ./graphify-out/csharp.json

The tool asks the installed SDK to convert the file-based app temporarily, honors its #:sdk, #:property, #:package, #:project, and #:include directives, and remaps source locations back to the repository. The SDK and any referenced packages/projects must be available on the host.

Integrate with Graphify

Add the skills to a coding-agent project

Graphify’s general-purpose skill and this enricher’s C# skill are intended to be installed together. Install Graphify’s skill for the agent platform you use, then copy this repository’s .agents/skills/graphify-csharp/SKILL.md into the consuming repository at the same relative path:

graphify install --platform codex
mkdir -p .agents/skills/graphify-csharp
cp /path/to/graphify-csharp/.agents/skills/graphify-csharp/SKILL.md \
  .agents/skills/graphify-csharp/SKILL.md

Keep the two skills separate. The graphify skill handles generic extraction, queries, paths, and exports; graphify-csharp adds the C# workflow and tells the agent to run graphify-csharp before Graphify consumes the graph. If your agent uses a different project-skill directory, place the same C# SKILL.md there according to that agent’s conventions.

Run the enricher from the root of the repository being analyzed, before every Graphify rebuild. The output is already Graphify extraction JSON, so Graphify can build its directed graph from the file:

dotnet tool install --global Graphify.CSharp --framework net10.0

graphify-csharp \
  --input ./src/MyProduct.sln \
  --root . \
  --configuration Release \
  --output ./graphify-out/csharp.json

graphify query "Which methods call the service?" \
  --graph ./graphify-out/csharp.json

For a normal C# repository, make those commands the repository’s Graphify entry point so the semantic enricher runs every time. For example, save this as scripts/graphify-csharp.sh and use it instead of calling graphify directly:

#!/usr/bin/env bash
set -euo pipefail

root="$(git rev-parse --show-toplevel)"
input="${GRAPHIFY_CSHARP_INPUT:-$root/src/MyProduct.sln}"
output="$root/graphify-out/csharp.json"

graphify-csharp \
  --input "$input" \
  --root "$root" \
  --configuration "${GRAPHIFY_CSHARP_CONFIGURATION:-Release}" \
  --output "$output"

exec graphify query "$@" --graph "$output"

Make it executable with chmod +x scripts/graphify-csharp.sh, then run scripts/graphify-csharp.sh "Which methods call the service?". The wrapper regenerates the semantic layer before every query. If your Graphify workflow uses extract, path, explain, or an export command instead, keep the same first graphify-csharp step and pass --graph ./graphify-out/csharp.json to that command.

The raw csharp.json file is the authoritative C# evidence and preserves parallel relationships such as calls and overrides. Graphify’s clustered NetworkX view may normalize multiple relationships between the same endpoints into one edge, so retain the raw file when an audit depends on relation-level detail. If the repository also contains non-C# material, keep its normal Graphify extraction as a separate graph and merge the two Graphify JSON documents with Graphify’s merge-graphs command. Do not merge this output with a name-only C# extraction without an explicit ID-join policy.

The CLI currently writes one complete Graphify extraction document. Large repositories can be sharded later, but every shard must remain a complete nodes/edges/hyperedges document with stable IDs. Plain JSON Lines fragments are not Graphify extraction files by themselves.

Graphify’s current merge-graphs command is intended for independent repositories or graph sources: it prefixes each input’s IDs and normalizes the merged view. It should not be used as the same-repository shard merger when stable C# IDs or parallel relations matter. A future shard mode needs a deterministic same-repository merger that unions nodes by ID, preserves the multigraph edge identity, validates cross-shard endpoints, and emits the same complete Graphify document.

The package is currently built from this repository as version 0.1.5 while the API and Graphify integration settle. For local development, replace the install command with:

dotnet run --project src/Graphify.CSharp.Cli --framework net10.0 -- --input ./src/MyProduct.sln --root .

--target-framework is optional. The loader resolves a single project target automatically; pass it when a project targets multiple frameworks. An ambiguous multi-target project fails with an actionable message instead of producing a mixed graph. For a file-based app it is forwarded to the SDK conversion/restore step when supplied.

Output

The output keeps Graphify’s required nodes, edges, and hyperedges arrays. Edges are directed from source/caller to target/contract and use EXTRACTED for Roslyn-resolved facts. v0.1 emits calls, references, inherits, implements, and overrides; compiler-bound call arguments also reference their source formal-parameter declarations. Node properties include the full symbol key, namespace, project, target framework, and declaration kind. The catalog covers namespaces, named types, constructors, methods/operators/local functions, properties/indexers, fields/enum values, events, parameters, locals, type parameters, aliases, labels, and query range variables. graphify_csharp contains only the versioned extractor metadata and loader or declaration-extraction diagnostics. If Roslyn exposes a source declaration shape that cannot yet be given a stable identity, the enricher skips that declaration, records an actionable diagnostic with its source location, and continues emitting the rest of the graph. C# 15 closed hierarchy types additionally carry is_closed=true.

The enricher does not classify callers or decide whether a declaration is safe to remove. Reflection, dependency injection, generated code, native callbacks, and other runtime mechanisms are outside static extraction and must be handled by the consuming analysis.

Scope of v0.1

Included:

  • .sln, .slnx, and .csproj loading through MSBuildWorkspace, plus SDK file-based .cs apps with source-location remapping;
  • overload-aware symbol identity including project and TFM context;
  • direct calls, constructors, method groups, properties, fields, enum values, events, scoped declarations, formal call parameters, declaration-header, attribute, generic, and typeof references;
  • compiler-selected members for operators, conversions, deconstruction, foreach/await/using, property/event accessors, patterns, ranges, collection expressions, interpolated string handlers, and fixed/pointer syntax;
  • inheritance, interface implementation, and virtual override relationships;
  • C# 14 extension blocks, field-backed properties, partial constructors/events, explicit compound-assignment operators, and newer lambda/assignment forms;
  • C# 15 collection-expression arguments, union declarations and case-type references, closed hierarchies, extension indexers, labeled jumps, and memory-safety syntax when the net11.0 tool asset is selected;
  • cross-project symbol resolution with conservative ambiguity handling;
  • stable Graphify JSON and a dependency-free command-line parser.

Not a runtime reachability proof. Interface/virtual dispatch expansion, reflection heuristics, DI container modeling, and host callbacks are deliberately bounded in v0.1 and will be added only with explicit provenance and fixtures. Unnamed syntax artifacts and compiler-generated implementation details are not separate graph nodes in v0.1.

Development

dotnet test Graphify.CSharp.sln --configuration Release
dotnet build Graphify.CSharp.sln --configuration Release
dotnet pack src/Graphify.CSharp.Cli --configuration Release

The full solution and package commands validate both target assets and require the .NET 10 and .NET 11 SDKs. A .NET 10-only checkout can still run the focused net10.0 build/test commands with --framework net10.0.

To verify byte-for-byte repeatability against a fixture or another solution:

./scripts/check-deterministic-extraction.sh \
  --input ./src/MyProduct/MyProduct.sln \
  --root . \
  --configuration Release

The pinned real-world semantic end-to-end gate restores, builds, and tests this solution, packs the CLI, installs that package into an isolated temporary tool directory, then clones a third-party C# project into the ignored .e2e/ directory, checks multiple declaration kinds and relationships, and runs extraction twice:

./scripts/run-real-world-e2e.sh

The watcher lifecycle smoke test can be run directly from the solution tests; it covers missed-event backup detection, recovery after watcher failure, local refresh IPC, and bounded event delivery:

dotnet test Graphify.CSharp.sln --configuration Release \
  --filter FullyQualifiedName~IncrementalWatcherHostTests

The packaged watcher lifecycle test exercises the real tool process, local refresh client, alternate-output routing, backup scan, restart, rebuild, and Graphify JSON validation:

./scripts/run-watcher-e2e.sh

CI and the release workflow pass an existing package to this script and set a long backup interval so the source-change portion also verifies the real FileSystemWatcher event path. To check a package locally in the same mode:

GRAPHIFY_CSHARP_WATCH_E2E_PACKAGE_PATH=artifacts/Graphify.CSharp.0.1.5.nupkg \
GRAPHIFY_CSHARP_WATCH_E2E_FRAMEWORK=net10.0 \
GRAPHIFY_CSHARP_WATCH_E2E_TARGET_FRAMEWORK=net10.0 \
GRAPHIFY_CSHARP_WATCH_E2E_SCAN_INTERVAL=01:00:00 \
./scripts/run-watcher-e2e.sh

Set GRAPHIFY_CSHARP_WATCH_E2E_FRAMEWORK=net11.0 to exercise the .NET 11 tool asset. The fixture remains net10.0 because the tool runtime and the analyzed project target are independent.

The temporary feed and tool directory are removed on exit; the pinned source checkout and Graphify output remain under .e2e/ for inspection. Override the fixture URL, commit, TFM, configuration, or local package version with the GRAPHIFY_CSHARP_E2E_* environment variables when testing another pinned fixture.

The repository’s reusable development contract is in .agents/skills/graphify-csharp/SKILL.md. See docs/USAGE.md for output details and docs/COMPATIBILITY.md for the supported v0.1 path, and docs/RELEASING.md for NuGet publishing setup.

Product 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.  net11.0 is compatible. 
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.1.6 0 9/12/2026
0.1.6-preview.1 0 9/11/2026
0.1.5 46 9/11/2026
0.1.5-preview.1 37 9/11/2026
0.1.4 54 9/10/2026
0.1.1 51 9/8/2026
0.1.0 49 9/8/2026
0.1.0-preview.4 45 9/8/2026
0.1.0-preview.3 47 9/8/2026