Skip to content

Getting Started

Build and run your first Spectra workflow in a new .NET app.

In this guide, you will:

  1. create a console project
  2. install Spectra
  3. register one LLM provider
  4. run a simple workflow
  5. connect two nodes with shared state

By the end, you will understand Spectra's core model:

  • nodes do work
  • edges define flow
  • state carries data between steps

Prerequisites

You need:

  • .NET 10 SDK
  • an API key for a supported provider such as OpenRouter, OpenAI, or Anthropic

This guide uses OpenRouter for the simplest first setup.


Create a project

dotnet new console -n HelloSpectra
cd HelloSpectra
dotnet add package Spectra
dotnet add package Spectra.Extensions
  • Spectra contains the workflow engine and builders
  • Spectra.Extensions adds provider integrations like OpenAI, Anthropic, Gemini, Ollama, and OpenRouter

Set your API key

export OPENROUTER_API_KEY="your-api-key"
$env:OPENROUTER_API_KEY="your-api-key"

Using another provider?

You can swap AddOpenRouter(...) for AddOpenAI(...), AddAnthropic(...), AddGemini(...), or AddOllama(...).

Your workflow definition stays the same. Only provider setup changes.


Your first workflow

Create or replace Program.cs with this:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Spectra.Contracts.Execution;
using Spectra.Contracts.State;
using Spectra.Registration;
using Spectra.Workflow;

var host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        services.AddSpectra(spectra =>
        {
            spectra.AddOpenRouter(config =>
            {
                config.ApiKey = Environment.GetEnvironmentVariable("OPENROUTER_API_KEY")!;
                config.Model = "openai/gpt-4o-mini";
            });

            spectra.AddConsoleEvents();
        });
    })
    .Build();

var workflow = WorkflowBuilder.Create("hello")
    .AddAgent("assistant", "openrouter", "openai/gpt-4o-mini", agent => agent
        .WithSystemPrompt("You are a friendly assistant."))
    .AddAgentNode("greet", "assistant", node => node
        .WithUserPrompt("Say hello to {{inputs.name}} in a creative way.")
        .WithMaxIterations(1))
    .Build();

var runner = host.Services.GetRequiredService<IWorkflowRunner>();

var state = new WorkflowState();
state.Inputs["name"] = "World";

var result = await runner.RunAsync(workflow, state);

if (result.Context.TryGetValue("greet", out var greetObj)
    && greetObj is IDictionary<string, object?> greetDict
    && greetDict.TryGetValue("response", out var greeting))
{
    Console.WriteLine(greeting);
}

What is happening here?

This example has four parts:

1. Register Spectra

services.AddSpectra(...)

This adds the Spectra runtime to the normal .NET dependency injection container.

2. Register a provider

spectra.AddOpenRouter(...)

This tells Spectra how to call a model provider.

3. Define a workflow

var workflow = WorkflowBuilder.Create("hello") ...

This creates a workflow with one node:

  • an agent named assistant
  • a node named greet
  • a prompt that uses {{inputs.name}}

4. Run with state

var state = new WorkflowState();
state.Inputs["name"] = "World";
WorkflowState is the shared data for the run.

It has three dictionaries:

  • Inputs for incoming values provided at launch time
  • Context for data produced by steps during execution
  • Artifacts for named outputs like files or results

When a node completes, Spectra writes its outputs into Context under the node's id. So the greeting is read from:

result.Context["greet"]

Output key not found

Make sure you read the node output using the correct node id:

result.Context["greet"]

Run it

dotnet run

You should see workflow events in the console, then the generated greeting.

A typical run looks like this:

[WorkflowStarted] hello
[StepStarted] greet
[StepCompleted] greet
[WorkflowCompleted] hello

Hello, World! It's great to meet you.

The exact greeting will vary by model.

What matters is:

  • the greet node runs
  • its output is written to workflow state
  • you read it back from nodes.greet.output

Add a second node

Now let's connect two steps together.

This workflow:

  1. generates a greeting
  2. passes that greeting to another node
  3. translates it to French
var workflow = WorkflowBuilder.Create("greet-and-translate")
    .AddAgent("assistant", "openrouter", "openai/gpt-4o-mini", agent => agent
        .WithSystemPrompt("You are a helpful assistant."))
    .AddAgentNode("greet", "assistant", node => node
        .WithUserPrompt("Say hello to {{inputs.name}}. Reply with just the greeting.")
        .WithMaxIterations(1))
    .AddAgentNode("translate", "assistant", node => node
        .WithUserPrompt("Translate to French: {{nodes.greet.output}}")
        .WithMaxIterations(1))
    .AddEdge("greet", "translate")
    .Build();

The key expression is:

{{nodes.greet.output}}

That value comes from the first node's output.

This is Spectra's core model:

  • nodes perform work
  • edges connect the steps
  • state carries values through the graph

Once that clicks, the rest of Spectra becomes much easier to understand.


C# or JSON?

You can define workflows in either format:

  • use C# when you want workflow definitions close to application code
  • use JSON when you want workflows to be easy to edit, review, or deploy without recompiling

Start with C# first.

Then move to JSON when you want external workflow definitions.

See JSON workflow definitions →


Common first-run issues

OPENROUTER_API_KEY is null

Your environment variable is not set in the shell where you ran dotnet run.

Provider not found

Make sure you registered the same provider name you use in the workflow:

.AddAgent("assistant", "openrouter", ...)

Output key not found

Make sure you read the node output using the correct node id:

result["nodes.greet.output"]

What's next?

  • Workflows — understand nodes, edges, and graph structure
  • State — learn how data moves through a workflow
  • Providers — switch between OpenAI, Anthropic, Gemini, Ollama, and OpenRouter
  • Agent Step — customize prompts, iterations, and model behavior
  • Runner — learn how workflows execute