Atom is an opinionated, type-safe build automation framework for .NET. It enables you to define your build logic in C#, debug it like standard code, and automatically generate CI/CD configuration files for GitHub Actions and Azure DevOps.
| Package | What it does |
|---|---|
| Invex.Atom.Build | Core framework: build definitions, targets, parameters, hosting. |
| Invex.Atom.Workflows | Workflow definitions, triggers, options, and the Gen target. |
| Invex.Atom.Module.Dotnet | .NET CLI wrappers and build, test, pack, publish, and NuGet helpers. |
| Invex.Atom.Module.GitHubWorkflows | GitHub Actions workflow and Dependabot generation. |
| Invex.Atom.Module.DevOpsWorkflows | Azure DevOps Pipelines workflow generation. |
| Invex.Atom.Module.AzureKeyVault | Azure Key Vault secrets provider. |
| Invex.Atom.Module.AzureStorage | Azure Blob Storage artifact provider. |
| Invex.Atom.Module.GitVersion | GitVersion-based build ID and version. |
| Invex.Atom.Tool | The atom .NET global tool for running builds from any directory. |
- Zero context switching. Write build logic in C# alongside your application code.
- IntelliSense and debugging. Step through your build process using your IDE.
- CI/CD agnostic. Define logic once; Atom generates the YAML for GitHub Actions and Azure DevOps.
- Modular. Pull in capabilities via NuGet packages (GitVersion, Azure Key Vault, and more).
- Source generators. Targets and parameters are discovered automatically, so there is no registration boilerplate.
Atom build projects require the .NET 10 SDK. The libraries target net10.0.
Add the core package to your build project (commonly _atom/_atom.csproj):
dotnet add package Invex.Atom.BuildInstall the CLI once if you want to invoke builds from any directory:
dotnet tool install --global Invex.Atom.Tool-
Create a .NET 10 project:
dotnet new console -n _atom
-
Replace the contents of
_atom.csproj:<Project Sdk="Microsoft.NET.Sdk.Worker"> <PropertyGroup> <TargetFramework>net10.0</TargetFramework> <RootNamespace>Atom</RootNamespace> </PropertyGroup> <ItemGroup> <PackageReference Include="Invex.Atom.Build" Version="3.*" /> </ItemGroup> </Project>
-
Replace
Program.cswithIBuild.cs:using Invex.Atom.Build.Definition; using Invex.Atom.Build.Hosting; namespace Atom; [BuildDefinition] [GenerateEntryPoint] internal interface IBuild : IBuildDefinition { Target HelloWorld => t => t .DescribedAs("Prints a hello world message to the console") .Executes(() => Logger.LogInformation("Hello, World!")); }
-
Run the target with
atom HelloWorld(ordotnet run --project _atom -- HelloWorld):26-06-06 +10:00 Invex.Atom.Build.BuildExecutor: 01:16:47.552 INF Executing build HelloWorld Prints a hello world message to the console 26-06-06 +10:00 HelloWorld | Atom.Build: 01:16:47.616 INF Hello, World! Build Summary HelloWorld │ Succeeded │ <0.01s
Declare a parameter with [ParamDefinition] (or a secret with [SecretDefinition], which is masked in logs) and
require it on a target:
[ParamDefinition("my-name", "My name")]
string? MyName => GetParam(() => MyName);
[SecretDefinition("my-secret", "My secret")]
string? MySecret => GetParam(() => MySecret);
Target HelloWorld =>
t => t
.RequiresParam(nameof(MyName))
.RequiresParam(nameof(MySecret))
.Executes(() => Logger.LogInformation("I am {MyName} and my secret is {MySecret}.", MyName, MySecret));Run it with atom HelloWorld --my-name Frodo --my-secret TheOneRing. See
Parameters and
Secrets.
Targets run in dependency order, and parameters only need to be provided once:
Target Goodbye =>
t => t
.DescribedAs("Prints a goodbye message to the console")
.DependsOn(nameof(HelloWorld))
.Executes(() => Logger.LogInformation("Goodbye!"));atom Goodbye --my-name Frodo --my-secret TheOneRing runs HelloWorld and then Goodbye. See
Targets.
Reference Invex.Atom.Module.GitHubWorkflows, extend IWorkflowBuildDefinition, and declare a workflow:
using Invex.StructuredText.Expressions;
[BuildDefinition]
[GenerateEntryPoint]
internal interface IBuild : IWorkflowBuildDefinition, IGitHubWorkflows
{
// targets and parameters as above
IReadOnlyList<WorkflowDefinition> IWorkflowBuildDefinition.Workflows =>
[
new("Hello")
{
Triggers = [WorkflowTriggers.PushToMain],
Targets =
[
new(nameof(HelloWorld))
{
Options =
[
BuildOptions.Inject.Param(nameof(MyName), TextExpressions.GitHub.GitHubRepositoryOwner),
BuildOptions.Inject.Secret(nameof(MySecret)),
],
},
new(nameof(Goodbye)),
],
Types = [WorkflowTypes.GitHub.Action],
},
];
}atom Gen writes .github/workflows/Hello.yml, with one job per target and the parameter and secret injected from
GitHub. See Workflow Definitions.
A build can also be a single Atom.cs file run with dotnet run Atom.cs HelloWorld:
#:sdk Microsoft.NET.Sdk.Worker
#:package Invex.Atom.Build@3.*
[BuildDefinition]
[GenerateEntryPoint]
internal interface IBuild : IBuildDefinition
{
Target HelloWorld => t => t.Executes(() => Logger.LogInformation("Hello, World!"));
}See Your First Build.
Full documentation: https://invex-games.github.io/atom/
| Guide | Contents |
|---|---|
| Introduction | What Atom is, when to use it, and how the packages fit together. |
| Your First Build | Create a project-based or file-based build and run it. |
| Base vs Workflow Build | IBuildDefinition vs IWorkflowBuildDefinition. |
| Core Concepts | Build definitions, targets, parameters, secrets, artifacts, variables, file system, hosting, and more. |
| Workflows | Workflow definitions, triggers, options, variables across jobs, and debugging. |
| Modules | .NET, GitHub Workflows, DevOps Workflows, Azure Key Vault, Azure Storage, and GitVersion. |
| Built-in Targets | SetupBuildInfo, ValidateBuild, and Gen. |
| Developer Guide | Writing modules, custom providers, source generators, and testing. |
| CLI Reference | Command-line options and the atom global tool. |
| API Reference | Key types per package, linked into the generated reference. |
The solution is Invex.Atom.slnx and requires the .NET 10 SDK:
dotnet build Invex.Atom.slnx
dotnet test Invex.Atom.slnxAtom builds itself with the build definition in _atom/. Build or preview the DocFX documentation with:
atom BuildDocs
atom ServeDocsdotnet run --project _atom -- <target> is equivalent to atom <target>.
The Atom libraries are human-made, however GitHub Copilot completions have been used on a superficial level.
Generative AI was also used to assist in writing tests and documentation.
Atom is released under the MIT License.