Prompt Management¶
Spectra lets you manage prompts as reusable templates instead of hardcoded strings.
Instead of embedding long system prompts directly in workflow code, you can store them in Markdown files, give them stable IDs, attach metadata, and reference them from agents or steps.
This makes prompts easier to:
- reuse across workflows
- version in Git
- review like normal project assets
- update without rewriting workflow logic
- organize by role, task, or domain
In Spectra, prompt management is the layer between prompt authoring and prompt execution.
- you author prompts as templates
- Spectra loads them into a registry
- steps and agents resolve them by ID
- the renderer fills in variables at runtime
Why manage prompts outside code?¶
For small experiments, inline prompt strings are fine.
But once workflows grow, inline prompts become harder to maintain:
- the same prompt logic gets duplicated
- prompt edits become mixed with code changes
- long prompt text makes workflows harder to read
- it becomes harder to review prompt changes separately
External prompt files solve that.
A typical Spectra setup keeps workflow structure in code or JSON, while prompt content lives in a prompts/ directory.
That separation makes workflows easier to understand and prompts easier to evolve.
The recommended approach: file-based prompts¶
The most common setup is to store prompts as Markdown files.
Example:
prompts/
├── agents/
│ ├── coder.md
│ ├── reviewer.md
│ └── planner.md
├── shared/
│ └── safety-guidelines.md
└── tasks/
└── summarize.md
This structure works well because it mirrors how teams think:
agents/for reusable system promptstasks/for user-task templatesshared/for common prompt fragments or guidance
You then register the directory during startup:
Once registered, prompts can be referenced by ID from agents and workflow steps.
How prompt IDs work¶
Each file gets a prompt ID based on its path.
The prompt directory root is stripped and the .md extension is removed.
| File Path | Prompt ID |
|---|---|
prompts/agents/coder.md |
agents/coder |
prompts/shared/safety-guidelines.md |
shared/safety-guidelines |
prompts/tasks/summarize.md |
tasks/summarize |
That means a file like:
can be referenced as:
This gives you stable, readable prompt references throughout your workflows.
Writing a prompt template¶
Prompt templates are normal text with {{variable}} placeholders.
Example:
You are a {{role}} working on the {{project}} project.
Summarize the following text in {{language}}:
{{inputs.text}}
At runtime, Spectra replaces the placeholders with values from workflow state and step inputs.
This makes prompts reusable without hardcoding environment-specific or task-specific values.
Front-matter metadata¶
Prompt files can include front-matter at the top.
Example:
---
id: agents/coder
name: Coder Agent
description: System prompt for the coding specialist
version: "2.1"
variables:
- language
- framework
---
You are a senior {{language}} developer specializing in {{framework}}.
Write clean, well-tested code. Always include error handling.
Follow the project's existing code style.
Front-matter is useful for:
- giving prompts human-readable names
- documenting what a prompt is for
- tracking prompt versions
- listing expected variables
- attaching extra metadata for tooling or governance
Supported fields¶
| Field | Type | Description |
|---|---|---|
id |
string | Overrides the file-path-derived ID |
name |
string | Human-readable name |
description |
string | What the prompt is for |
version |
string | Version tag for tracking changes |
variables |
list | Expected {{variable}} names |
Any other front-matter keys are stored in the prompt metadata dictionary.
Important note about variables¶
The variables list is for documentation and discoverability.
It does not enforce runtime validation by itself.
In other words:
- it tells people what the prompt expects
- it does not block rendering if a value is missing
Actual missing-variable behavior is controlled by the renderer mode.
Using prompt files with agents¶
One of the best uses of prompt management is storing agent system prompts as files.
Example:
builder.AddPromptsFromDirectory("./prompts");
builder.AddAgent("coder", "openai", "gpt-4o", agent => agent
.WithSystemPromptRef("agents/coder"));
Here, the agent does not carry a large inline system prompt.
Instead, it references:
This keeps agent registration clean and makes the prompt easier to update independently.
Using prompt files with workflow steps¶
Workflow steps can also use inline prompts or prompt references.
Example:
workflow.AddAgentNode("code", "coder", node => node
.WithUserPrompt("Implement a REST endpoint for: {{inputs.task}}"));
In this example:
- the system prompt comes from the file-backed prompt registry
- the user prompt is inline
- both can still use template variables
This is a good pattern when:
- the reusable identity lives in a file
- the task-specific instruction is generated inline by the workflow
How variables are resolved¶
When Spectra renders a prompt, it resolves variables from multiple places.
The sources are merged in this order, with later values winning:
state.Inputsstate.Context- step
Inputsexcept internal__keys
That means node-level inputs can override broader workflow values when needed.
This makes prompt rendering flexible while still fitting naturally into Spectra's shared-state model.
Missing variable behavior¶
Sometimes a prompt references a variable that is not available at render time.
The renderer supports three behaviors:
| Mode | Behavior |
|---|---|
LeaveTemplate |
Keeps {{variable}} unchanged in the output |
ReplaceWithEmpty |
Replaces missing variables with an empty string |
ThrowException |
Throws KeyNotFoundException during rendering |
The default is:
That default is helpful during development because unresolved placeholders remain visible instead of silently disappearing.
Hot reload during development¶
When you are iterating on prompts, restarting the app after every prompt edit is slow.
Spectra supports hot reload for file-based prompt registries:
With file watching enabled, changes to .md prompt files are picked up automatically.
This is especially useful when you are:
- tuning agent behavior
- refining system prompts
- testing workflow wording
- collaborating with non-developers on prompt text
In-memory prompts¶
For tests, experiments, or generated prompts, Spectra also supports in-memory registration.
var registry = new InMemoryPromptRegistry();
registry.Register(new PromptTemplate
{
Id = "test/greeting",
Content = "Hello, {{name}}! Welcome to {{project}}."
});
builder.AddPrompts(registry);
This is useful when you want:
- lightweight tests
- prompts created programmatically
- no file-system dependency
- a simple setup for prototypes
If you do not register prompts from a directory, an in-memory registry is the simplest fallback.
How Spectra resolves prompts¶
When a step needs a prompt, Spectra checks a resolution chain.
The most important idea is:
- inline prompts take highest priority
- referenced prompts come next
- agent-level defaults are used when step-level values are absent
System prompt resolution¶
For system prompts, Spectra checks in this order:
1. systemPrompt input
2. agent.SystemPromptRef
3. agent.SystemPrompt
4. promptId input
5. no system prompt
User prompt resolution¶
For user prompts, Spectra checks in this order:
This gives you flexibility:
- keep simple prompts inline
- move reusable prompts into files
- define stable agent identities once
- override behavior per step when needed
A practical mental model¶
A good way to think about Spectra prompt management is:
- prompt file = reusable content asset
- prompt ID = stable reference to that asset
- registry = where prompts are loaded and looked up
- renderer = fills template variables at runtime
- agent or step = the consumer of the rendered prompt
Once that clicks, the system becomes easy to reason about.
Under the hood: PromptTemplate¶
Internally, each prompt is represented as a PromptTemplate.
public class PromptTemplate
{
public required string Id { get; init; }
public required string Content { get; init; }
public string? Name { get; init; }
public string? Description { get; init; }
public string? Version { get; init; }
public List<string> Variables { get; init; } = [];
public Dictionary<string, object?> Metadata { get; init; } = [];
public string? FilePath { get; init; }
public DateTimeOffset? LoadedAt { get; init; }
}
At a high level:
Idis how the prompt is referencedContentis the template textVariablesdocuments expected inputs- the rest is metadata about the prompt and where it came from
Most users do not need to construct PromptTemplate directly unless they are working with in-memory registries or custom prompt tooling.
Recommended project pattern¶
A strong default setup for real projects looks like this:
- keep reusable system prompts in
prompts/agents/ - keep task prompts in
prompts/tasks/ - register prompts once at startup
- reference prompts by ID from agents
- use inline user prompts only when the instruction is highly workflow-specific
This keeps the system easy to scale as workflows grow.
Common issues¶
Prompt ID not found¶
Make sure the registered prompt directory and the referenced prompt ID match.
For example:
becomes:
Prompt changes are not picked up¶
Hot reload only works when file watching is enabled.
Variables are not being replaced¶
Check that the values exist in workflow inputs, context, or step inputs, and verify the renderer's missing-variable mode.
Prompt metadata is present but not enforced¶
Fields like variables help document a prompt, but they do not perform runtime validation by themselves.
What's next?¶
- Providers
Connect agents to OpenAI, Anthropic, Gemini, Ollama, OpenRouter, or compatible APIs.
- Prompt Steps
Learn where prompts are consumed in workflow execution.
- Agent Step
See how system prompts shape autonomous agent behavior.