.NET Foundation Statement on Open Source Maintenance Fees
Official statement from the .NET Foundation on Open Source Maintenance Fees
Official statement from the .NET Foundation on Open Source Maintenance Fees
In 2021 I posted here about my opinionated .NET console stack: Spectre.Console for CLI parsing, Microsoft.Extensions for DI/logging, and a custom template (Devlead.Console.Template) as an alternative to dotnet new console.
I've kept using that approach and built several CLI tools on it since. The original write-up is still here if useful for context:
https://www.devlead.se/posts/2021/2021-01-15-my-preferred-console-stack
The core recipe still feels right to me:
That part aged well.
The template-only approach had a flaw I did not appreciate enough in 2021.
Templates are great for scaffolding. They are poor for maintaining shared bootstrap code across many repos.
Once I had multiple console tools, every project had its own copy of the same Program glue: service collection setup, logging, config, Spectre wiring, etc. When bootstrap code changed (logging defaults, Spectre API updates, config additions), I was back to merging or copy/pasting fixes across repositories. That is the drift problem templates do not solve on their own.
I split responsibilities:
Program stubs)Devlead.Console) = versioned shared bootstrap compiled into the appSource packages ship .cs under contentFiles/cs/{tfm}/... with BuildAction=Compile. The glue code compiles into your assembly (debuggable, extendable) but updates like a normal package dependency.
Extension still happens in your project via partial methods:
public partial class Program
{
static partial void AddServices(IServiceCollection services)
{
services.AddSingleton<MyService>();
}
static partial void ConfigureApp(AppServiceConfig appServiceConfig)
{
appServiceConfig
.AddCommand<MyCommand>("run")
.WithDescription("Does the thing.")
.WithExample(["run"]);
appServiceConfig.SetApplicationName("mytool");
}
}
Scaffold is unchanged in spirit:
dotnet new install Devlead.Console.Template
dotnet new devleadconsole -n MyTool
Shared bootstrap updates via normal NuGet versioning:
dotnet add package Devlead.Console
I wrote a longer follow-up with the reasoning, packaging notes (Devlead.SourcePack), and real-world usage in tools like ARI/Blobify/DPI:
Full disclosure: I maintain the template and package (OSS/MIT). The main point of the post is the template vs source package split.
If you use a custom console template (your own or a third-party one), how do you handle bootstrap drift across multiple repos?
Curious what has worked for you, especially if you maintain a bunch of internal CLI tools.