Guides
Production Deployment
Checklist for deploying Open Harness workflows
Production Deployment
A practical checklist for running Open Harness in production.
Deployment Targets
- Node.js/Bun server: Run workflows behind an HTTP API
- Serverless: Supported for short-lived workflows (avoid long-running streams)
- Edge: For lightweight workflows with minimal dependencies
Example: Workflow API Service
import express from "express";
import { createWorkflow, ClaudeHarness } from "@open-harness/core";
const app = express();
app.use(express.json());
type State = { input: string; result: string | null };
const { agent, runReactive } = createWorkflow<State>();
const analyzer = agent({
prompt: "Analyze: {{ state.input }}",
activateOn: ["workflow:start"],
emits: ["analysis:complete"],
updates: "result",
});
const harness = new ClaudeHarness({
model: "claude-sonnet-4-20250514",
});
app.post("/analyze", async (req, res) => {
try {
const result = await runReactive({
agents: { analyzer },
state: { input: req.body.input, result: null },
harness,
endWhen: (s) => s.result !== null,
});
res.json({
result: result.state.result,
metrics: result.metrics,
});
} catch (error) {
res.status(500).json({ error: "Workflow failed" });
}
});
app.listen(3000, () => {
console.log("Workflow service on :3000");
});Error Handling
Handle workflow failures gracefully:
try {
const result = await runReactive({
agents: { analyzer },
state: initialState,
harness,
});
} catch (error) {
if (error instanceof HarnessError) {
// Harness API failure
logger.error("Harness failed", { error: error.message });
} else if (error instanceof TimeoutError) {
// Workflow timeout
logger.error("Workflow timeout", { durationMs: error.elapsed });
}
}Observability
Signal Logging
Log signals for debugging:
const result = await runReactive({
agents: { analyzer },
state: initialState,
harness,
});
// Log signal trace
for (const signal of result.signals) {
logger.info(`[${signal.name}]`, {
timestamp: signal.timestamp,
payload: signal.payload,
});
}Metrics
Extract metrics from results:
// Duration and activation count
console.log(`Duration: ${result.metrics.durationMs}ms`);
console.log(`Activations: ${result.metrics.activations}`);
// Count signals by type
const signalCounts = result.signals.reduce((acc, s) => {
acc[s.name] = (acc[s.name] || 0) + 1;
return acc;
}, {} as Record<string, number>);Security Best Practices
- Authentication: Protect endpoints that start workflows
- Rate limiting: Throttle runs per user or API key
- Input validation: Validate user input before
runReactive - Secrets management: Store harness credentials in environment variables
Environment Variables
| Variable | Description | Required |
|---|---|---|
LOG_LEVEL | Logging verbosity (trace, debug, info, warn, error) | Optional |
Authentication
Open Harness uses Claude Code subscription authentication. No API key is required - authentication is handled automatically when running from within Claude Code.
Pre-Production Checklist
- Validate workflows with test inputs
- Set appropriate timeouts
- Add structured logging
- Configure error handling
- Lock down network access and secrets
- Test recording/replay for CI