You can create extensions for .NET Interactive in order to create custom experiences including custom visualizations, new magic commands, new subkernels supporting additional languages, and more. Extensions can be distributed using NuGet packages. The extension is activated when the package is loaded by .NET Interactive using #r nuget
.
The simplest way to create an extension is to add a file called extension.dib
into a NuGet package and build the package so that extension.dib
is placed in a folder inside the package called interactive-extensions\dotnet
.
When a package is loaded using #r nuget
, if that file is found inside the package, then it will be run the code in extension.dib
after referencing your packages library (assuming the package contains a library). Because .dib
files support multiple languages, your extension can run code using any of the supported .NET Interactive languages, or even load new kernels with additional languages. The most common approach, though, and the one detailed below, is to use extension.dib
to simply call a method in your library.
The ClockExtension sample illustrates this approach. There's also walkthrough in the form of a notebook that shows you how to build and install it.
Here are most important details of the sample project:
-
The project contains a public
Load
method containing code to extend .NET Interactive. This can be any public method. Taking aKernel
parameter makes it straightforward to write tests for your extension code. -
The
extension.dib
file contains code to call this method, passing in the root kernel. (Note that this code doesn't containusing
directives so as not to clutter up the notebook user's IntelliSense.)#!csharp ClockExtension.ClockKernelExtension.Load(Microsoft.DotNet.Interactive.KernelInvocationContext.Current.HandlingKernel.RootKernel);
-
ClockExtension.csproj
includes a reference to theextension.dib
file that places it in the correct location in the NuGet package:<ItemGroup> <None Include="extension.dib" Pack="true" PackagePath="interactive-extensions/dotnet" /> </ItemGroup>
Give the sample notebook a try to see it working end to end on your machine.
Here are some of the more common things you might want to do when extending .NET Interactive.
You can create you own magic commands and add them to the available commands in your notebooks either by writing an extension or by defining them directly in the notebook code. Magic commands are defined using the APIs under the Microsoft.DotNet.Interactive.Directives
namespace to parse the user's input and define the associated actions performed by the magic command, as well as provide hover help and completions.
We'll use the example found in the ClockExtension
sample to go over the high-level usage of this API. This sample creates a magic command called #!clock
that can be used to display an SVG rendering of a clock showing the specified time.

Let's start by looking at the code used to define the magic command itself. This code creates a magic command (#!clock
) with three parameters (--hour
, --minute
, and --second
), which can be called as in the screen shot above. We'll go through the code step by step to explain how the API is used.
var hourParameter = new KernelDirectiveParameter("--hour", "The position of the hour hand");
var minuteParameter = new KernelDirectiveParameter("--minute", "The position of the minute hand");
var secondParameter = new KernelDirectiveParameter("--second", "The position of the second hand");
var clockDirective = new KernelActionDirective("#!clock")
{
Description = "Displays a clock showing the current or specified time.",
Parameters =
[
hourParameter,
minuteParameter,
secondParameter
]
};
A KernelActionDirective
is used to define a magic command and give it a name (#!clock
), which is the text used in code to invoke it. The KernelDirectiveParameter
class is used to define the parameters that the magic command accepts.
The names and descriptions for these objects are used to provide hover help and standard completions such as parameter names.


The next step is to add the KernelActionDirective
to the kernel where it will be in scope.
kernel.AddDirective<DisplayClock>(clockDirective, (displayClock, context) =>
{
context.Display(
SvgClock.DrawSvgClock(
displayClock.Hour,
displayClock.Minute,
displayClock.Second));
return Task.CompletedTask;
});
Several things are happening in the above code.
kernel.AddDirective
adds the the directive (clockDirective
) to the kernel.- The generic parameter (
DisplayClock
) defines the type of the associatedKernelCommand
that will be instantiated and sent to the kernel when the magic command is invoked. - The delegate defines the code that will run to handle the
DisplayClock
command.
Here's the definition of DisplayClock
:
public class DisplayClock : KernelDirectiveCommand
{
public int Hour { get; set; }
public int Minute { get; set; }
public int Second { get; set; }
}
Note that KernelDirectiveCommand
inherits KernelCommand
, so you can send the DisplayClock
command directly using the Kernel.SendAsync
method, just like any other KernelCommand
.
The extension also changes the default formatting for the System.DateTime
type. This feature is the basis for creating custom visualizations for any .NET type. Before installing the extension, the default output just used the DateTime.ToString
method:
After installing the extension, we get the much more appealing clock drawing, with the hands set to the current time:
The code that does this is also found in the sample's Load
method:
Formatter.Register<DateTime>((date, writer) =>
{
writer.Write(date.DrawSvgClock());
}, "text/html");
The Formatter
API can be used to customize the output for a given .NET type (System.DateTime
) for a mime type ("txt/html"
).