Summary
Kestra's script plugin ecosystem covers more than a dozen languages — Python, Node.js, Ruby, Go, Deno, and more — but has no support for running C# scripts. This gap is especially felt by .NET-heavy teams (financial services, enterprise, Windows-centric shops) who orchestrate C# Windows Services, console apps, and analytical scripts.
Adding a plugin-script-dotnet sub-module with Script and Commands tasks would let these teams keep their C# code as first-class orchestration steps inside Kestra flows, eliminating the need for brittle wrapper scripts or separate runner services. C# scripting is widely cited as an underserved area in orchestration tooling — a first-mover Kestra integration would be a real differentiator.
Motivation
Without native C# script support, .NET-centric teams face common workarounds:
- Wrapping
dotnet run calls inside shell tasks — no syntax support, poor DX, error messages swallowed by the shell layer
- Rewriting analytics in Python just to fit the orchestrator
- Maintaining a separate runner service that Kestra calls over HTTP, adding operational overhead and an extra failure point
The target audience spans financial services teams (C# Windows Services for portfolio and trading workflows), enterprise platform engineers, and data analysts who work alongside Java/Python colleagues but prefer C# for business logic. The integration slots naturally alongside the existing PowerShell sub-plugin — both serve .NET-platform users, with C# covering the programmatic layer where PowerShell covers the operational/admin layer.
Context
No prior .NET/C# scripting issue found across kestra-io. The existing plugin-script-powershell sub-plugin is the nearest reference implementation — the architecture (Docker runner, Commands + Script tasks, RunnerType, AbstractLogConsumer) translates directly.
Implementation should use dotnet-script to run .csx (C# Script) files. This gives users a familiar scripting experience with inline NuGet package references (#r "nuget:PackageName,version"), full C# language features without a project file, and rapid iteration without a build step.
API Reference
- Official docs: https://github.com/dotnet-script/dotnet-script
- Authentication: N/A — local subprocess runtime, no auth required
- Base URL pattern: N/A — subprocess-based execution
- Runtime tool:
dotnet-script CLI (dotnet tool install -g dotnet-script)
- Docker image:
mcr.microsoft.com/dotnet/sdk:10.0 (LTS)
- Script format:
.csx — C# Script files with inline NuGet directives
Gradle Dependencies
Add to plugin-script-dotnet/build.gradle:
// No additional JVM-side runtime dependencies needed.
// The .NET SDK is provided via the Docker/task-runner image.
// Kestra's internal HTTP client and Jackson are provided by the framework.
// Follow the same dependency block as plugin-script-powershell.
dependencies {
implementation project(':plugin-script')
}
dotnet-script runs as a subprocess via the task runner infrastructure — no JVM-side SDK is required.
Kestra framework inclusions (do not add as dependencies): Kestra's internal HTTP client (io.kestra.core.http.client) and Jackson serializers are provided by the framework.
Plugin Structure
- Repository:
kestra-io/plugin-scripts (new sub-module plugin-script-dotnet)
- Namespace:
io.kestra.plugin.scripts.dotnet
- Sub-plugins: None — flat structure
- Categories:
DATA, INFRASTRUCTURE
Task class naming: Use Script and Commands — consistent with every other sub-plugin in this repository. Do not prefix with DotNet, CSharp, or similar; the fully-qualified type already carries namespace context.
Suggested Tasks
- Add
plugin-script-dotnet sub-module: register in settings.gradle, create build.gradle, scaffold package structure
- Implement
Script task — executes an inline .csx C# script via dotnet-script
- Implement
Commands task — runs arbitrary shell commands inside a .NET SDK container
- Add
package-info.java with @PluginSubGroup(category = PluginSubGroup.PluginCategory.DATA)
- Add
metadata/index.yaml and plugin icon SVG (io.kestra.plugin.scripts.dotnet.svg)
- Write unit + integration tests — happy path, failure scenarios, NuGet package reference support
- Add sanity-check YAML flow under
src/test/resources/sanity-checks/
- Add how-to doc at
src/main/resources/doc/io.kestra.plugin.scripts.dotnet.md
YAML Examples
Example 1 — Inline C# script with NuGet package
id: dotnet_inline_script
namespace: company.team
description: Run an inline C# script with a NuGet dependency
tasks:
- id: hello_csharp
type: io.kestra.plugin.scripts.dotnet.Script
script: |
#r "nuget:Newtonsoft.Json,13.0.3"
using Newtonsoft.Json;
var data = new { message = "Hello from Kestra", timestamp = DateTime.UtcNow };
Console.WriteLine(JsonConvert.SerializeObject(data));
Example 2 — Run dotnet commands against a script file
id: dotnet_commands
namespace: company.team
description: Run a dotnet-script file with a dynamic input
inputs:
- id: data_file
type: STRING
tasks:
- id: run_dotnet
type: io.kestra.plugin.scripts.dotnet.Commands
commands:
- dotnet-script analyze.csx --input {{ inputs.data_file }}
Example 3 — Scheduled portfolio analysis
id: portfolio_daily
namespace: company.team
description: Run portfolio analysis on weekday mornings
triggers:
- id: daily
type: io.kestra.plugin.core.trigger.Schedule
cron: "0 6 * * MON-FRI"
tasks:
- id: run_portfolio_analysis
type: io.kestra.plugin.scripts.dotnet.Script
script: |
#r "nuget:CsvHelper,33.0.1"
// load positions, compute P&L, emit CSV
Console.WriteLine("Portfolio analysis complete: " + DateTime.UtcNow.ToString("o"));
Acceptance Criteria
Functional
Kestra Plugin Coding Standards
Documentation & Structure
Repository Setup Checklist
This is a new sub-module in an existing repository — no new repository scaffolding or Terraform apply is required.
Add to Sanity Check page
Add plugin-script-dotnet to the Sanity check Notion page.
View as Artifact
Summary
Kestra's script plugin ecosystem covers more than a dozen languages — Python, Node.js, Ruby, Go, Deno, and more — but has no support for running C# scripts. This gap is especially felt by .NET-heavy teams (financial services, enterprise, Windows-centric shops) who orchestrate C# Windows Services, console apps, and analytical scripts.
Adding a
plugin-script-dotnetsub-module withScriptandCommandstasks would let these teams keep their C# code as first-class orchestration steps inside Kestra flows, eliminating the need for brittle wrapper scripts or separate runner services. C# scripting is widely cited as an underserved area in orchestration tooling — a first-mover Kestra integration would be a real differentiator.Motivation
Without native C# script support, .NET-centric teams face common workarounds:
dotnet runcalls inside shell tasks — no syntax support, poor DX, error messages swallowed by the shell layerThe target audience spans financial services teams (C# Windows Services for portfolio and trading workflows), enterprise platform engineers, and data analysts who work alongside Java/Python colleagues but prefer C# for business logic. The integration slots naturally alongside the existing PowerShell sub-plugin — both serve .NET-platform users, with C# covering the programmatic layer where PowerShell covers the operational/admin layer.
Context
No prior .NET/C# scripting issue found across kestra-io. The existing
plugin-script-powershellsub-plugin is the nearest reference implementation — the architecture (Docker runner,Commands+Scripttasks,RunnerType,AbstractLogConsumer) translates directly.Implementation should use dotnet-script to run
.csx(C# Script) files. This gives users a familiar scripting experience with inline NuGet package references (#r "nuget:PackageName,version"), full C# language features without a project file, and rapid iteration without a build step.API Reference
dotnet-scriptCLI (dotnet tool install -g dotnet-script)mcr.microsoft.com/dotnet/sdk:10.0(LTS).csx— C# Script files with inline NuGet directivesGradle Dependencies
Add to
plugin-script-dotnet/build.gradle:Plugin Structure
kestra-io/plugin-scripts(new sub-moduleplugin-script-dotnet)io.kestra.plugin.scripts.dotnetDATA,INFRASTRUCTURESuggested Tasks
plugin-script-dotnetsub-module: register insettings.gradle, createbuild.gradle, scaffold package structureScripttask — executes an inline.csxC# script viadotnet-scriptCommandstask — runs arbitrary shell commands inside a .NET SDK containerpackage-info.javawith@PluginSubGroup(category = PluginSubGroup.PluginCategory.DATA)metadata/index.yamland plugin icon SVG (io.kestra.plugin.scripts.dotnet.svg)src/test/resources/sanity-checks/src/main/resources/doc/io.kestra.plugin.scripts.dotnet.mdYAML Examples
Example 1 — Inline C# script with NuGet package
Example 2 — Run dotnet commands against a script file
Example 3 — Scheduled portfolio analysis
Acceptance Criteria
Functional
Scripttask runs inline.csxC# scripts viadotnet-scriptCommandstask runs arbitrary shell commands in a .NET SDK container#r "nuget:...") work in theScripttask./gradlew test)./gradlew buildKestra Plugin Coding Standards
Property<T>— no legacy@PluginProperty(dynamic = true)on new code@PluginProperty(secret = true)@Schemaannotation@SuperBuilder,@ToString,@EqualsAndHashCode,@Getter,@NoArgsConstructor)runContext.logger()onlyio.kestra.core.serializersProperty<T>fields support Kestra expression language (template rendering)Documentation & Structure
@Plugin(examples = ...)entries each setfull = truewith a complete runnable flow (id + namespace + tasks/triggers){{ secret('SECRET_NAME') }}package-info.javawith@PluginSubGroup(category = PluginSubGroup.PluginCategory.DATA)metadata/index.yamland plugin icon SVG presentsrc/main/resources/doc/io.kestra.plugin.scripts.dotnet.mdRepository Setup Checklist
This is a new sub-module in an existing repository — no new repository scaffolding or Terraform apply is required.
Add to Sanity Check page
Add
plugin-script-dotnetto the Sanity check Notion page.View as Artifact