Signal
Signal type reference
Signal
All communication in Open Harness uses typed signals.
Type Definition
interface Signal {
id: string; // Unique identifier ("sig_abc123")
name: string; // Signal name ("analysis:complete")
payload: unknown; // Signal-specific data
timestamp: string; // ISO timestamp
source?: {
agent?: string; // Emitting agent
parent?: string; // Parent signal ID (causality)
};
}Signal ID Format
Signal IDs use the format sig_<random>:
"sig_abc123def456"IDs are unique within a workflow execution.
Signal Names
Signal names use colon-separated namespaces:
| Namespace | Examples |
|---|---|
workflow: | workflow:start, workflow:end |
agent: | agent:activated, agent:completed |
harness: | harness:start, harness:end |
text: | text:delta, text:complete |
thinking: | thinking:delta, thinking:complete |
tool: | tool:call, tool:result |
state: | state:analysis:changed |
| Custom | analysis:complete, review:done |
Payload Types
Workflow Signals
// workflow:start
{ state: TState; agents: string[] }
// workflow:end
{
state: TState;
metrics: { durationMs: number; activations: number };
terminatedEarly: boolean;
}Agent Signals
// agent:activated
{ agent: string; triggeredBy: string }
// agent:skipped
{ agent: string; reason: string }
// agent:completed
{ agent: string; output: unknown }Harness Signals
// harness:start
{ model: string }
// harness:end
{
usage?: { inputTokens: number; outputTokens: number };
cost?: number;
sessionId?: string;
}
// harness:error
{ error: string; retryAfter?: number }Text Signals
// text:delta
{ content: string }
// text:complete
{ content: string }Thinking Signals
// thinking:delta
{ content: string }
// thinking:complete
{ content: string }Tool Signals
// tool:call
{ id: string; name: string; input: unknown }
// tool:result
{ id: string; name: string; output: unknown; error?: string }State Signals
// state:{key}:changed
{ value: unknown; previousValue: unknown }Source Tracking
The source field tracks signal origin:
{
name: "analysis:complete",
source: {
agent: "analyzer", // Which agent emitted
parent: "sig_xyz789", // Parent signal (trigger)
},
}Use for causality debugging:
const chain = result.signals.filter(s => s.source?.parent === targetId);Creating Signals
Harnesses create signals using createSignal:
import { createSignal } from "@open-harness/core";
yield createSignal("harness:start", { model: "my-model" });
yield createSignal("text:delta", { content: "Hello" });
yield createSignal("harness:end", { usage: { inputTokens: 10, outputTokens: 5 } });Working with Signals
Filter by Name
const agentSignals = result.signals.filter(s => s.name.startsWith("agent:"));Extract Text
const textComplete = result.signals.find(s => s.name === "text:complete");
const output = textComplete?.payload.content;Calculate Totals
const totalTokens = result.signals
.filter(s => s.name === "harness:end")
.reduce((sum, s) => {
const usage = s.payload.usage || { inputTokens: 0, outputTokens: 0 };
return sum + usage.inputTokens + usage.outputTokens;
}, 0);Type Guards
Use type guards for type-safe access:
function isHarnessEnd(signal: Signal): signal is Signal & { payload: { usage: Usage } } {
return signal.name === "harness:end";
}
const harnessEnds = result.signals.filter(isHarnessEnd);