Skip to main content
The plugin system lets you add any data to your graph and visualize it. Inspired by Houdini’s attribute system, plugins write attributes to nodes—then the renderer uses those attributes to change colors, sizes, and more.

The Houdini Way

In Houdini, you don’t hardcode “this point is red.” Instead, you set an attribute Cd = (1, 0, 0) and the renderer reads it. CodeGraph works the same way:
1

Plugin writes attributes

Plugin reads external data and writes attributes to nodes
2

Plugin declares visualization

Plugin defines how to visualize those attributes
3

Renderer applies visuals

Frontend reads attributes and applies colors/sizes

Plugin Interface

public interface IOverlayPlugin
{
    string Id { get; }
    string Name { get; }
    string Description { get; }
    OverlayDefinition[] Overlays { get; }

    Task ApplyAsync(IGraphStorage storage, CancellationToken ct);
    Task RemoveAsync(IGraphStorage storage, CancellationToken ct);
}

Example: Test Coverage Plugin

public class TestCoveragePlugin : IOverlayPlugin
{
    public string Id => "test-coverage";
    public string Name => "Test Coverage";

    public OverlayDefinition[] Overlays => new[]
    {
        new OverlayDefinition
        {
            Id = "line-coverage",
            Name = "Line Coverage",
            Type = OverlayType.Color,
            Attribute = "coverage:percent",
            Legend = new GradientLegend
            {
                Stops = new[]
                {
                    new LegendStop(0, "#ef4444", "0%"),
                    new LegendStop(50, "#f59e0b", "50%"),
                    new LegendStop(100, "#22c55e", "100%")
                }
            }
        }
    };

    public async Task ApplyAsync(IGraphStorage storage, CancellationToken ct)
    {
        var coverage = await ParseCoverageReport(_reportPath);
        var nodes = await storage.GetNodesAsync(ct);

        foreach (var node in nodes)
        {
            if (coverage.TryGetValue(node.FilePath, out var data))
            {
                await storage.UpdateNodeAttributesAsync(node.Id, new Dictionary<string, object>
                {
                    ["coverage:percent"] = data.LinePercent
                }, ct);
            }
        }
    }

    public async Task RemoveAsync(IGraphStorage storage, CancellationToken ct)
    {
        await storage.RemoveAttributesByPrefixAsync("coverage:", ct);
    }
}

Registering Plugins

Via Dependency Injection

services.AddSingleton<IOverlayPlugin, TestCoveragePlugin>();
services.AddSingleton<IOverlayPlugin, GitActivityPlugin>();

Via Plugin Discovery

Place DLLs in the plugins/ directory:
plugins/
├── CodeGraph.Plugin.Coverage.dll
├── CodeGraph.Plugin.GitActivity.dll
└── CodeGraph.Plugin.Quarterly.dll

Best Practices

Use Prefixed Attributes

Always prefix: myplugin:metric not metric

Clean Removal

Implement RemoveAsync with RemoveAttributesByPrefixAsync

Handle Missing Data

Not all nodes will have data. Skip gracefully.

Report Progress

For long operations, report progress.