Arlecchino 2026.8.5
dotnet add package Arlecchino --version 2026.8.5
NuGet\Install-Package Arlecchino -Version 2026.8.5
<PackageReference Include="Arlecchino" Version="2026.8.5" />
<PackageVersion Include="Arlecchino" Version="2026.8.5" />
<PackageReference Include="Arlecchino" />
paket add Arlecchino --version 2026.8.5
#r "nuget: Arlecchino, 2026.8.5"
#:package Arlecchino@2026.8.5
#addin nuget:?package=Arlecchino&version=2026.8.5
#tool nuget:?package=Arlecchino&version=2026.8.5

A terminal UI framework for .NET where a view is a plain class built by
Microsoft.Extensions.DependencyInjection and the routes between views are written by a source
generator, so nothing is registered by hand.

Above: Arlecchino.Commander, an application built on the framework. The dialog, the notification and the keys screen are the framework's own. Sixteen more screens — panels, marks, the menu, file operations, servers, SSH, notifications — are in the readme on GitHub.
Quick start
dotnet add package Arlecchino
A view is a class implementing IArlecchinoView. Constructor parameters come from the container:
public class DefaultView : IArlecchinoView
{
private readonly Surface _surface;
public DefaultView(Surface surface) => _surface = surface;
public void Draw()
{
_surface.AppendLine("hello", Theme.Header, Align.Center);
}
public ViewRoute Handle(ConsoleKeyInfo key) =>
key.Key == ConsoleKey.A ? ViewKind.About : ViewRoute.None;
public (string Key, string Description)[] Hints() => [("a", "about")];
}
Routes come from a source generator that finds every IArlecchinoView in the project, so
ViewKind.About reads like an enum while staying a plain string route the framework can name.
Starting the application is nine lines:
using MyApp.Navigation;
var builder = Host.CreateApplicationBuilder(args);
builder.Services
.AddArlecchino(options => options.MinimumWidth = 60)
.AddGeneratedViews()
.AddGeneratedStores()
.AddGeneratedCommands()
.StartAt(ViewKind.Default);
await builder.Build().RunAsync();
ViewKind and AddGeneratedViews are written into $(RootNamespace).Navigation — MyApp.Navigation
above — so the file that starts the application needs that using. Both appear as soon as the package
is referenced, and ViewKind fills up with a route per view.
Modals for text, passwords, email and links, numbers, sliders, toggles, single and multiple choice,
dates, times and colours come with the framework, along with a command palette, a hints box and a
file picker. Numbers are drawn by Sparkline, BarChart<T> and Gauge.
Why this one
A view is tested like any other class. The headless host lives in its own package:
dotnet add package Arlecchino.Testing
It builds the whole application against a terminal in memory, and frames are drawn when a test asks for one — there is nothing to wait for and nothing to race against:
using var app = new ArlecchinoTestHost(configure: arlecchino =>
arlecchino.AddGeneratedViews().StartAt(ViewKind.Default));
Assert.Contains("hello", app.Frame(), StringComparison.Ordinal);
app.Press(ConsoleKey.A);
Assert.Equal(ViewKind.About, app.Navigator.CurrentRoute);
Work on a timer is tested the same way: app.Advance(TimeSpan.FromSeconds(1)) moves the clock rather
than sleeping, and the next frame shows what fell due.
Undo comes with the state. State lives in atoms: writing one notifies whatever reads it and marks
the frame stale, so nothing asks for a repaint by hand. Which edits can be taken back is decided by
the type — a TrackedAtom<T> records its writes, a LocalAtom<T> does not — and AtomHistory,
resolved from the container, walks them with Undo and Redo. Writes made inside Group() come
back as one step, so a dialog that changes three fields is undone once. Many things at once are an
AtomsList<T> or an AtomsMap<TKey, TValue>: they change in place — appended to, trimmed, keyed —
and every call still notifies, still asks for a frame and still records a step of its own.
Logging does not draw over the frame. An ILogger resolved from the container writes into a
buffer the framework keeps, and Ctrl+L shows that buffer over the running application. The provider
is registered by default, since one that wrote to standard output would draw straight across the
screen.
Native AOT is checked rather than claimed. Each build publishes the sample as a native binary and asks it for a frame; a native build that draws nothing fails the build.
The keys and the words belong to the application. The key map is a record, so
keymap with { Cancel = new(ConsoleKey.Q) } rebinds one key and every hint and palette entry
relabels itself. Every string the framework draws is a delegate, and layouts that are not Latin are
typed as they are — or read from where the keys sit, with UseKeysByPosition(), when shortcuts
matter more than typing.
Where it sits
Spectre.Console writes to the console rather than
running a screen, and points at Terminal.Gui for interactive work.
Terminal.Gui is the mature one: fifty built-in views, a
repository that goes back to 2017, an Application/Window/View model that controls are added to,
and no hosting integration. Spectre.Tui is a few
months old and marked "under construction". Termina is the
closest in intent — dependency injection, the Generic Host, ASP.NET Core-style routes — and gets there
through reactive MVVM.
Arlecchino keeps the view a plain class: constructor injection, a Draw, a Handle, and routes the
generator writes from the views it finds. It is also younger than all four by a wide margin, and the
only one that still builds for net8.0 — the others require .NET 10. Checked in July 2026. The longer
comparison is in the readme on GitHub.
Packages
| Package | Contents |
|---|---|
Arlecchino.Core |
Surface, Theme, TermColor, KeyText, IArlecchinoTerminal — the renderer, no DI — and atoms with their undo history |
Arlecchino |
views, navigation, modals, commands, hosting, DI, async stores, and the generator |
Arlecchino.Pictures |
PNG, JPEG, BMP, Netpbm, QOI and Targa read into pixels |
Arlecchino.Testing |
ArlecchinoTestHost — the headless host applications write their tests against |
Links
Documentation · Changelog · Source and issues · Contributing · Security
MIT.
| Product | Versions 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 was computed. 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. |
-
net10.0
- Arlecchino.Core (>= 2026.8.5)
- Microsoft.Extensions.DependencyInjection (>= 10.0.11)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.11)
- Microsoft.Extensions.Hosting.Abstractions (>= 10.0.11)
- Microsoft.Extensions.Logging (>= 10.0.11)
-
net8.0
- Arlecchino.Core (>= 2026.8.5)
- Microsoft.Extensions.DependencyInjection (>= 10.0.11)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.11)
- Microsoft.Extensions.Hosting.Abstractions (>= 10.0.11)
- Microsoft.Extensions.Logging (>= 10.0.11)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Arlecchino:
| Package | Downloads |
|---|---|
|
Arlecchino.Testing
Headless test host for Arlecchino applications: a fake terminal, key and mouse input, and frames captured as plain text. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2026.8.5 | 62 | 8/19/2026 |
| 2026.8.4 | 111 | 8/16/2026 |
| 2026.8.3 | 97 | 8/16/2026 |
| 2026.8.2 | 102 | 8/16/2026 |
| 2026.8.1 | 108 | 8/14/2026 |
| 5.0.0 | 148 | 8/8/2026 |
| 4.0.0 | 178 | 8/3/2026 |
| 3.1.0 | 136 | 8/2/2026 |
| 3.0.0 | 145 | 8/1/2026 |
| 2.13.0 | 120 | 7/29/2026 |
| 2.12.0 | 127 | 7/29/2026 |
| 2.11.0 | 118 | 7/29/2026 |
| 2.10.0 | 113 | 7/29/2026 |
| 2.9.0 | 123 | 7/29/2026 |
| 2.8.0 | 131 | 7/29/2026 |
| 2.7.0 | 114 | 7/29/2026 |
| 2.6.1 | 141 | 7/29/2026 |
| 2.6.0 | 120 | 7/28/2026 |
| 2.5.0 | 116 | 7/28/2026 |
| 2.4.1 | 109 | 7/28/2026 |
What changed in this version: https://github.com/The1fEst/Arlecchino/blob/master/CHANGELOG.md#202685