Use when building rich terminal UIs in .NET with Spectre.Console. Covers tables, trees, progress bars, prompts, live rendering, markup formatting, and the Spectre.Console.Cli command framework.
USE FOR: rendering tables and grids in the terminal, progress bars and spinners, interactive prompts and selections, colorized and styled console output, building CLI apps with Spectre.Console.Cli
DO NOT USE FOR: executing external processes (use cliwrap), argument parsing without UI (use commandline-cheatsheet), building web UIs (use Blazor), logging output (use ILogger with console provider)
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
Use when building rich terminal UIs in .NET with Spectre.Console. Covers tables, trees, progress bars, prompts, live rendering, markup formatting, and the Spectre.Console.Cli command framework.
USE FOR: rendering tables and grids in the terminal, progress bars and spinners, interactive prompts and selections, colorized and styled console output, building CLI apps with Spectre.Console.Cli
DO NOT USE FOR: executing external processes (use cliwrap), argument parsing without UI (use commandline-cheatsheet), building web UIs (use Blazor), logging output (use ILogger with console provider)
Spectre.Console is a .NET library for building beautiful, modern console applications with rich text rendering, tables, trees, progress bars, interactive prompts, and live-updating displays. It also provides Spectre.Console.Cli, a command framework for building structured CLI applications with dependency injection, type-safe settings, and automatic help generation.
using Spectre.Console;
var root = new Tree("[bold yellow]Solution[/]");
var srcNode = root.AddNode("[blue]src/[/]");
var apiNode = srcNode.AddNode("[blue]MyApp.Api/[/]");
apiNode.AddNode("Program.cs");
apiNode.AddNode("Startup.cs");
apiNode.AddNode("[dim]appsettings.json[/]");
var domainNode = srcNode.AddNode("[blue]MyApp.Domain/[/]");
domainNode.AddNode("Entities/");
domainNode.AddNode("Services/");
var testNode = root.AddNode("[blue]tests/[/]");
testNode.AddNode("MyApp.Tests/");
AnsiConsole.Write(root);
Progress Bars
using Spectre.Console;
await AnsiConsole.Progress()
.AutoClear(false)
.Columns(new ProgressColumn[]
{
new TaskDescriptionColumn(),
new ProgressBarColumn(),
new PercentageColumn(),
new RemainingTimeColumn(),
new SpinnerColumn()
})
.StartAsync(async ctx =>
{
var downloadTask = ctx.AddTask("[green]Downloading packages[/]", maxValue: 100);
var buildTask = ctx.AddTask("[blue]Building project[/]", maxValue: 100);
var testTask = ctx.AddTask("[yellow]Running tests[/]", maxValue: 100);
while (!ctx.IsFinished)
{
await Task.Delay(50);
if (!downloadTask.IsFinished)
downloadTask.Increment(2.5);
elseif (!buildTask.IsFinished)
buildTask.Increment(1.8);
elseif (!testTask.IsFinished)
testTask.Increment(3.0);
}
});
using Spectre.Console;
// Text inputvar name = AnsiConsole.Ask<string>("What is your [green]name[/]?");
// Text with default valuevar city = AnsiConsole.Ask("What [green]city[/] do you live in?", "Seattle");
// Password / secret inputvar password = AnsiConsole.Prompt(
new TextPrompt<string>("Enter [red]password[/]:")
.Secret()
.Validate(p => p.Length >= 8
? ValidationResult.Success()
: ValidationResult.Error("Password must be at least 8 characters")));
// Confirmationvar proceed = AnsiConsole.Confirm("Deploy to [red]production[/]?", defaultValue: false);
// Single selectionvar framework = AnsiConsole.Prompt(
new SelectionPrompt<string>()
.Title("Select a [green]framework[/]:")
.PageSize(10)
.AddChoiceGroup("Frontend", "React", "Vue", "Angular")
.AddChoiceGroup("Backend", "ASP.NET Core", "FastAPI", "Express"));
// Multi-selectionvar features = AnsiConsole.Prompt(
new MultiSelectionPrompt<string>()
.Title("Select [green]features[/] to enable:")
.Required()
.InstructionsText("[grey](Press [blue]<space>[/] to toggle, [green]<enter>[/] to accept)[/]")
.AddChoices("Authentication", "Caching", "Rate Limiting",
"Logging", "Health Checks", "Swagger"));
Console.WriteLine($"Selected: {string.Join(", ", features)}");
Live Display
Update the terminal in real time with live rendering.
using Spectre.Console;
var table = new Table().AddColumn("Time").AddColumn("Event");
await AnsiConsole.Live(table)
.AutoClear(false)
.Overflow(VerticalOverflow.Ellipsis)
.StartAsync(async ctx =>
{
for (int i = 0; i < 10; i++)
{
await Task.Delay(500);
table.AddRow(
DateTime.Now.ToString("HH:mm:ss"),
$"[green]Event {i + 1}[/] processed successfully");
ctx.Refresh();
}
});
Panels and Layout
using Spectre.Console;
var panel = new Panel(
new Markup("[bold]Application Status[/]\n\nAll systems operational."))
{
Header = new PanelHeader("[green] Dashboard [/]"),
Border = BoxBorder.Rounded,
Padding = new Padding(2, 1),
BorderStyle = new Style(Color.Green)
};
AnsiConsole.Write(panel);
// Bar chartvar chart = new BarChart()
.Label("[bold underline]Request Count by Endpoint[/]")
.CenterLabel()
.AddItem("GET /api/users", 1200, Color.Green)
.AddItem("POST /api/orders", 850, Color.Blue)
.AddItem("GET /api/products", 2100, Color.Yellow)
.AddItem("DELETE /api/sessions", 340, Color.Red);
AnsiConsole.Write(chart);
Exception Formatting
using Spectre.Console;
try
{
thrownew InvalidOperationException("Database connection failed",
new TimeoutException("Connection timed out after 30 seconds"));
}
catch (Exception ex)
{
AnsiConsole.WriteException(ex, new ExceptionSettings
{
Format = ExceptionFormats.ShortenEverything | ExceptionFormats.ShowLinks,
Style = new ExceptionStyle
{
Message = new Style(Color.Red),
Exception = new Style(Color.Grey),
Method = new Style(Color.Yellow),
Path = new Style(Color.Blue)
}
});
}
Spectre.Console.Cli (Command Framework)
Build structured CLI applications with typed settings and dependency injection.
using Spectre.Console;
using Spectre.Console.Cli;
using System.ComponentModel;
var app = new CommandApp();
app.Configure(config =>
{
config.AddCommand<DeployCommand>("deploy")
.WithDescription("Deploy the application")
.WithExample("deploy", "--environment", "staging", "--verbose");
config.AddBranch("db", db =>
{
db.AddCommand<MigrateCommand>("migrate")
.WithDescription("Run database migrations");
db.AddCommand<SeedCommand>("seed")
.WithDescription("Seed the database");
});
});
return app.Run(args);
publicclassDeploySettings : CommandSettings
{
[CommandOption("-e|--environment")]
[Description("Target environment")]
[DefaultValue("staging")]
publicstring Environment { get; init; } = "staging";
[CommandOption("-v|--verbose")]
[Description("Enable verbose output")]
publicbool Verbose { get; init; }
[CommandOption("--dry-run")]
[Description("Simulate deployment without making changes")]
publicbool DryRun { get; init; }
publicoverride ValidationResult Validate()
{
var validEnvs = new[] { "development", "staging", "production" };
if (!validEnvs.Contains(Environment.ToLower()))
return ValidationResult.Error($"Invalid environment: {Environment}");
return ValidationResult.Success();
}
}
publicclassDeployCommand : AsyncCommand<DeploySettings>
{
publicoverrideasync Task<int> ExecuteAsync(CommandContext context, DeploySettings settings)
{
if (settings.Environment == "production" && !settings.DryRun)
{
if (!AnsiConsole.Confirm("[red]Deploy to PRODUCTION?[/]", defaultValue: false))
return1;
}
await AnsiConsole.Status()
.StartAsync($"Deploying to {settings.Environment}...", async ctx =>
{
ctx.Status("Building artifacts...");
await Task.Delay(2000);
ctx.Status("Uploading...");
await Task.Delay(1500);
ctx.Status("Verifying...");
await Task.Delay(1000);
});
AnsiConsole.MarkupLine($"[green]Deployed to {settings.Environment}![/]");
return0;
}
}
Best Practices
Use AnsiConsole.MarkupLine with Spectre markup tags ([green], [bold], [underline]) instead of Console.Write with ANSI escape codes for portable colorized output that degrades gracefully on terminals without color support.
Call .EscapeMarkup() on any user-provided strings before interpolating them into markup templates to prevent markup injection (e.g., user input containing [red] would break rendering).
Use SelectionPrompt<T> and MultiSelectionPrompt<T> for interactive selection rather than asking users to type values manually, which reduces input errors and improves UX.
Use AnsiConsole.Status() with a spinner for short operations (under 10 seconds) and AnsiConsole.Progress() with named tasks for longer operations where users need to see which step is running.
Override Validate() on CommandSettings subclasses to enforce business rules (e.g., environment must be one of development/staging/production) with clear error messages before command execution.
Use config.AddBranch in Spectre.Console.Cli to group related subcommands (e.g., db migrate, db seed) rather than prefixing command names manually.
Set AutoClear(false) on Progress and Live renderers when the final output should remain visible after completion, rather than being cleared from the terminal.
Use Table.Border(TableBorder.Rounded) with BorderColor(Color.Grey) for a polished look; avoid TableBorder.None unless the data is already visually structured.
Add the Spectre.Console.Analyzer NuGet package to get compile-time warnings for common mistakes like unescaped markup and incorrect color names.
Use new ExceptionSettings { Format = ExceptionFormats.ShortenEverything } when displaying exceptions to users to reduce noise, and include ExceptionFormats.ShowLinks in development to get clickable file paths in supported terminals.