@wundr.io/orchestrator-daemon
v1.0.6
Published
Orchestrator Daemon for agent orchestration and session management
Maintainers
Readme
@wundr.io/orchestrator-daemon
Machine-level supervisor daemon for orchestrating Claude Code and Claude Flow sessions with real-time WebSocket communication, distributed session management, and MemGPT-inspired tiered memory architecture.
Overview
The Orchestrator Daemon is a production-ready, enterprise-grade daemon for managing AI agent sessions at scale. It provides:
- WebSocket Server - Real-time bidirectional communication with clients (Neolith, CLI tools, web apps)
- Session Management - Spawn, monitor, and orchestrate multiple Claude Code/Flow sessions
- Tiered Memory Architecture - MemGPT-inspired three-tier memory (scratchpad/episodic/semantic)
- Distributed Features - Federation, load balancing, session migration across daemon nodes
- Token Budget Management - Track, alert, and enforce API usage limits
- Prometheus Metrics - Real-time monitoring and observability
- Charter-Based Governance - Safety heuristics and resource limit enforcement
- Neolith Integration - Built-in API client for seamless integration with Neolith web app
Architecture
┌─────────────────────────────────────────────────────────────────┐
│ Orchestrator Daemon │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ WebSocket │ │ Session │ │ Memory │ │
│ │ Server │◄──►│ Manager │◄──►│ Manager │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ ▲ │ │ │
│ │ ▼ ▼ │
│ │ ┌──────────────┐ ┌──────────────┐ │
│ │ │ Charter │ │ Scratchpad │ │
│ │ │ Governance │ │ (Working) │ │
│ │ └──────────────┘ └──────────────┘ │
│ │ │ │
│ │ ┌──────────────┐ ┌──────────────┐ │
│ └────────────│ Federation │ │ Episodic │ │
│ │ Coordinator │ │ (7 days) │ │
│ └──────────────┘ └──────────────┘ │
│ │ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Prometheus │ │ Token │ │ Semantic │ │
│ │ Metrics │ │ Budget │ │ (Permanent) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
└────────────────────────┬───────────────────────────────────────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌──────────┐
│ Neolith │ │ CLI │ │ Custom │
│ Web App │ │ Tools │ │ Clients │
└─────────┘ └─────────┘ └──────────┘Quick Start
Get the daemon running in 5 minutes:
Prerequisites
- Node.js 18.0.0 or higher
- pnpm (recommended) or npm
- Redis (optional, for distributed features)
- PostgreSQL (optional, for persistent storage)
Installation
# With pnpm (recommended)
pnpm add @wundr.io/orchestrator-daemon
# Or with npm
npm install @wundr.io/orchestrator-daemonConfiguration
- Copy the example environment file:
cp .env.example .env- Edit
.envand set required variables:
# REQUIRED: OpenAI API key
OPENAI_API_KEY=sk-your-api-key-here
# Server configuration
DAEMON_PORT=8787
DAEMON_HOST=127.0.0.1
# Optional: Redis for distributed features
REDIS_URL=redis://localhost:6379
# Optional: Neolith integration
NEOLITH_API_URL=http://localhost:3000
NEOLITH_API_KEY=vp_your_key_here
NEOLITH_API_SECRET=your_secret_hereRunning the Daemon
Option 1: CLI (Standalone)
# Start with default settings
orchestrator-daemon
# With custom port
orchestrator-daemon --port 9090
# With verbose logging
orchestrator-daemon --verbose
# With custom config file
orchestrator-daemon --config ./my-config.jsonOption 2: Via Wundr CLI
# Start the daemon
wundr orchestrator start
# Check status
wundr orchestrator status
# View logs (follow mode)
wundr orchestrator logs -f
# Stop daemon
wundr orchestrator stopOption 3: Programmatic
import { OrchestratorDaemon } from '@wundr.io/orchestrator-daemon';
const daemon = new OrchestratorDaemon({
name: 'orchestrator-daemon',
port: 8787,
host: '127.0.0.1',
maxSessions: 100,
heartbeatInterval: 30000,
shutdownTimeout: 10000,
verbose: false,
});
// Start the daemon
await daemon.start();
console.log('Daemon is running on ws://127.0.0.1:8787');
// Graceful shutdown
process.on('SIGTERM', async () => {
await daemon.stop();
process.exit(0);
});Verify It's Running
# Check health endpoint
curl http://127.0.0.1:8787/health
# Check Prometheus metrics
curl http://127.0.0.1:9090/metrics
# Or use the health check script
./scripts/health-check.shYou should see:
{
"status": "healthy",
"timestamp": "2025-12-01T12:00:00.000Z"
}Configuration Reference
All environment variables with descriptions:
Core Configuration
| Variable | Default | Description |
|----------|---------|-------------|
| OPENAI_API_KEY | required | OpenAI API key for AI-powered orchestration |
| OPENAI_MODEL | gpt-4o-mini | OpenAI model (gpt-4-turbo, gpt-4, gpt-3.5-turbo) |
| OPENAI_ORG_ID | - | OpenAI organization ID (optional) |
| OPENAI_BASE_URL | - | Custom OpenAI endpoint URL (optional) |
Alternative AI Provider
| Variable | Default | Description |
|----------|---------|-------------|
| ANTHROPIC_API_KEY | - | Anthropic API key for Claude models |
| ANTHROPIC_MODEL | claude-3-sonnet-20240229 | Claude model to use |
Server Configuration
| Variable | Default | Description |
|----------|---------|-------------|
| DAEMON_PORT | 8787 | WebSocket server port |
| DAEMON_HOST | 127.0.0.1 | Host address (use 0.0.0.0 for all interfaces) |
| DAEMON_MAX_SESSIONS | 100 | Maximum concurrent sessions |
| DAEMON_VERBOSE | false | Enable verbose logging |
| DAEMON_NAME | orchestrator-daemon | Daemon identifier |
Health & Heartbeat
| Variable | Default | Description |
|----------|---------|-------------|
| DAEMON_HEARTBEAT_INTERVAL | 30000 | Health check interval (ms) |
| DAEMON_HEALTH_CHECK_INTERVAL | 60000 | Overall health check interval (ms) |
| DAEMON_SHUTDOWN_TIMEOUT | 10000 | Graceful shutdown timeout (ms) |
Redis (Distributed Features)
| Variable | Default | Description |
|----------|---------|-------------|
| REDIS_URL | - | Redis connection URL |
| REDIS_PASSWORD | - | Redis password (if auth enabled) |
| REDIS_DB | 0 | Redis database number |
| REDIS_CONNECT_TIMEOUT | 5000 | Connection timeout (ms) |
PostgreSQL (Persistent Storage)
| Variable | Default | Description |
|----------|---------|-------------|
| DATABASE_URL | - | PostgreSQL connection URL |
| DATABASE_POOL_SIZE | 10 | Connection pool size |
| DATABASE_CONNECT_TIMEOUT | 5000 | Connection timeout (ms) |
Distributed Orchestration
| Variable | Default | Description |
|----------|---------|-------------|
| CLUSTER_NAME | orchestrator-cluster | Cluster name for daemon federation |
| LOAD_BALANCING_STRATEGY | least-loaded | Strategy: round-robin, least-loaded, weighted, hash-based |
| REBALANCE_INTERVAL | 300000 | Session rebalancing interval (ms) |
| MIGRATION_TIMEOUT | 30000 | Session migration timeout (ms) |
Neolith Integration
| Variable | Default | Description |
|----------|---------|-------------|
| NEOLITH_API_URL | http://localhost:3000 | Neolith API server URL |
| NEOLITH_API_KEY | - | Neolith API key (vp_...) |
| NEOLITH_API_SECRET | - | Neolith API secret |
Logging
| Variable | Default | Description |
|----------|---------|-------------|
| LOG_LEVEL | info | Log level: debug, info, warn, error |
| LOG_FORMAT | json | Log format: json, text |
| LOG_FILE | - | Log file path (logs to stdout if not set) |
| LOG_ROTATION_ENABLED | true | Enable log file rotation |
| LOG_MAX_SIZE | 10 | Max log file size (MB) before rotation |
| LOG_MAX_FILES | 5 | Number of rotated log files to keep |
Security
| Variable | Default | Description |
|----------|---------|-------------|
| DAEMON_JWT_SECRET | required | JWT secret (CHANGE IN PRODUCTION!) |
| DAEMON_JWT_EXPIRATION | 24h | JWT token expiration time |
| DAEMON_CORS_ENABLED | false | Enable CORS |
| DAEMON_CORS_ORIGINS | http://localhost:3000 | Allowed CORS origins (comma-separated) |
| DAEMON_RATE_LIMIT_ENABLED | true | Enable rate limiting |
| DAEMON_RATE_LIMIT_MAX | 100 | Max requests per window |
| DAEMON_RATE_LIMIT_WINDOW | 60000 | Rate limit window (ms) |
Monitoring
| Variable | Default | Description |
|----------|---------|-------------|
| METRICS_ENABLED | true | Enable Prometheus metrics endpoint |
| METRICS_PORT | 9090 | Prometheus metrics port |
| METRICS_PATH | /metrics | Metrics endpoint path |
| HEALTH_CHECK_ENABLED | true | Enable health check endpoint |
| HEALTH_CHECK_PATH | /health | Health check endpoint path |
Memory Management
| Variable | Default | Description |
|----------|---------|-------------|
| DAEMON_MAX_HEAP_MB | 2048 | Maximum heap memory (MB) |
| DAEMON_MAX_CONTEXT_TOKENS | 128000 | Max context tokens per session |
| MEMORY_COMPACTION_ENABLED | true | Enable memory compaction |
| MEMORY_COMPACTION_THRESHOLD | 0.8 | Memory compaction threshold (0.0-1.0) |
Token Budget
| Variable | Default | Description |
|----------|---------|-------------|
| TOKEN_BUDGET_DAILY | 1000000 | Daily token budget |
| TOKEN_BUDGET_WEEKLY | 5000000 | Weekly token budget |
| TOKEN_BUDGET_MONTHLY | 20000000 | Monthly token budget |
| TOKEN_BUDGET_ALERTS_ENABLED | true | Enable budget alerts |
| TOKEN_BUDGET_ALERT_THRESHOLD | 0.8 | Alert threshold (80% = 0.8) |
WebSocket API
Connection
Connect to the WebSocket server:
import WebSocket from 'ws';
const ws = new WebSocket('ws://127.0.0.1:8787');
ws.on('open', () => {
console.log('Connected to orchestrator daemon');
});
ws.on('message', (data) => {
const message = JSON.parse(data.toString());
console.log('Received:', message);
});Message Types
Client → Server Messages
1. Spawn Session
Create a new agent session:
ws.send(JSON.stringify({
type: 'spawn_session',
payload: {
orchestratorId: 'orchestrator-1',
task: {
id: 'task-123',
type: 'code',
description: 'Implement authentication system',
priority: 'high',
status: 'pending',
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
},
sessionType: 'claude-code', // or 'claude-flow'
},
}));2. Execute Task
Execute a task in an existing session:
ws.send(JSON.stringify({
type: 'execute_task',
payload: {
sessionId: 'session_abc123',
task: {
id: 'task-456',
type: 'test',
description: 'Run integration tests',
priority: 'medium',
status: 'pending',
},
},
}));3. Get Session Status
Query session status:
ws.send(JSON.stringify({
type: 'session_status',
payload: {
sessionId: 'session_abc123',
},
}));4. Get Daemon Status
Get overall daemon status:
ws.send(JSON.stringify({
type: 'daemon_status',
}));5. Stop Session
Terminate a running session:
ws.send(JSON.stringify({
type: 'stop_session',
payload: {
sessionId: 'session_abc123',
},
}));6. Health Check
Ping the server:
ws.send(JSON.stringify({
type: 'health_check',
}));7. Ping/Pong
Keep connection alive:
ws.send(JSON.stringify({
type: 'ping',
}));Server → Client Responses
1. Session Spawned
{
"type": "session_spawned",
"sessionId": "session_abc123",
"status": "active",
"metadata": {
"createdAt": "2025-12-01T12:00:00.000Z"
}
}2. Task Executing
{
"type": "task_executing",
"sessionId": "session_abc123",
"taskId": "task-456"
}3. Task Completed
{
"type": "task_completed",
"sessionId": "session_abc123",
"taskId": "task-456",
"result": {
"success": true,
"output": "Tests passed: 42/42"
}
}4. Task Failed
{
"type": "task_failed",
"sessionId": "session_abc123",
"taskId": "task-456",
"error": "Timeout exceeded"
}5. Stream Start
AI model started streaming response:
{
"type": "stream_start",
"sessionId": "session_abc123",
"metadata": {
"model": "gpt-4o-mini"
}
}6. Stream Chunk
Incremental streaming data:
{
"type": "stream_chunk",
"data": {
"sessionId": "session_abc123",
"chunk": "Implementing authentication...",
"metadata": {
"tokens": 15
}
}
}7. Stream End
Stream completed:
{
"type": "stream_end",
"sessionId": "session_abc123",
"metadata": {
"totalTokens": 523,
"duration": 4200
}
}8. Tool Call Start
AI model invoking a tool:
{
"type": "tool_call_start",
"data": {
"sessionId": "session_abc123",
"toolName": "file_read",
"toolInput": {
"path": "/src/auth.ts"
},
"status": "started",
"timestamp": "2025-12-01T12:05:00.000Z"
}
}9. Tool Call Result
Tool execution completed:
{
"type": "tool_call_result",
"data": {
"sessionId": "session_abc123",
"toolName": "file_read",
"status": "completed",
"result": {
"content": "export function authenticate() {...}"
},
"timestamp": "2025-12-01T12:05:01.000Z"
}
}10. Daemon Status Response
{
"type": "daemon_status_response",
"status": {
"name": "orchestrator-daemon",
"uptime": 3600000,
"activeSessions": 5,
"maxSessions": 100,
"memoryUsageMB": 256,
"cpuUsagePercent": 15.5,
"version": "1.0.6"
}
}11. Health Check Response
{
"type": "health_check_response",
"healthy": true
}12. Pong
{
"type": "pong"
}13. Error
{
"type": "error",
"error": "Session not found",
"sessionId": "session_invalid"
}Example Client
Complete WebSocket client example:
import WebSocket from 'ws';
class OrchestratorClient {
private ws: WebSocket;
constructor(url: string = 'ws://127.0.0.1:8787') {
this.ws = new WebSocket(url);
this.setupHandlers();
}
private setupHandlers() {
this.ws.on('open', () => {
console.log('✓ Connected to daemon');
this.sendHealthCheck();
});
this.ws.on('message', (data) => {
const msg = JSON.parse(data.toString());
this.handleMessage(msg);
});
this.ws.on('error', (error) => {
console.error('WebSocket error:', error);
});
this.ws.on('close', () => {
console.log('Disconnected from daemon');
});
}
private handleMessage(msg: any) {
switch (msg.type) {
case 'session_spawned':
console.log(`Session spawned: ${msg.sessionId}`);
break;
case 'stream_chunk':
process.stdout.write(msg.data.chunk);
break;
case 'task_completed':
console.log(`Task completed: ${msg.taskId}`);
break;
case 'error':
console.error(`Error: ${msg.error}`);
break;
default:
console.log('Received:', msg);
}
}
sendHealthCheck() {
this.ws.send(JSON.stringify({ type: 'health_check' }));
}
spawnSession(task: any) {
this.ws.send(JSON.stringify({
type: 'spawn_session',
payload: {
orchestratorId: 'my-orchestrator',
task,
sessionType: 'claude-code',
},
}));
}
getDaemonStatus() {
this.ws.send(JSON.stringify({ type: 'daemon_status' }));
}
}
// Usage
const client = new OrchestratorClient();
// Spawn a session after connection
setTimeout(() => {
client.spawnSession({
id: 'task-1',
type: 'code',
description: 'Implement login feature',
priority: 'high',
status: 'pending',
});
}, 1000);Docker Usage
Quick Start with Docker Compose
1. Start all services (daemon, Redis, PostgreSQL):
docker-compose up -d2. View logs:
# All services
docker-compose logs -f
# Daemon only
docker-compose logs -f daemon3. Check status:
docker-compose ps4. Stop services:
docker-compose down5. Stop and remove volumes (clean slate):
docker-compose down -vDevelopment Mode
Use the development Docker Compose configuration for hot-reloading:
# Start in development mode
docker-compose -f docker-compose.dev.yml up
# Or use the script
npm run docker:devEnvironment Variables for Docker
Create a .env file in the package directory:
# Service versions
REDIS_PORT=6379
POSTGRES_PORT=5432
POSTGRES_DB=orchestrator
POSTGRES_USER=orchestrator
POSTGRES_PASSWORD=orchestrator_pass
# Daemon configuration
DAEMON_PORT=8787
METRICS_PORT=9090
NODE_ENV=production
LOG_LEVEL=info
# Session configuration
SESSION_TIMEOUT=3600000
MAX_SESSIONS=100
# Federation
ENABLE_FEDERATION=true
FEDERATION_PORT=8788
# Monitoring
ENABLE_METRICS=true
METRICS_INTERVAL=60000Custom Dockerfile
Build your own image:
# Build production image
docker build -t my-orchestrator-daemon .
# Build development image
docker build -f Dockerfile.dev -t my-orchestrator-daemon:dev .
# Run the custom image
docker run -d \
-p 8787:8787 \
-p 9090:9090 \
-e OPENAI_API_KEY=sk-your-key \
-e REDIS_HOST=redis \
--name orchestrator \
my-orchestrator-daemonHealth Checks
The Docker container includes built-in health checks:
# Check container health
docker inspect --format='{{.State.Health.Status}}' orchestrator-daemon
# View health check logs
docker inspect --format='{{range .State.Health.Log}}{{.Output}}{{end}}' orchestrator-daemonIntegration with Neolith
The daemon provides seamless integration with the Neolith web application.
Setup
1. Configure Neolith credentials in .env:
NEOLITH_API_URL=https://neolith.wundr.io
NEOLITH_API_KEY=vp_your_api_key_here
NEOLITH_API_SECRET=your_secret_here2. The daemon automatically connects on startup
Authentication Flow
┌─────────┐ ┌──────────┐ ┌─────────┐
│ Daemon │ │ Neolith │ │ Redis │
│ │ │ API │ │ │
└────┬────┘ └────┬─────┘ └────┬────┘
│ │ │
│ POST /api/daemon/auth │ │
│ (API key + secret) │ │
├──────────────────────────► │ │
│ │ │
│ JWT tokens (access+refresh)│ │
│ ◄──────────────────────────┤ │
│ │ │
│ Store tokens │ │
├────────────────────────────┼──────────────────────────►│
│ │ │
│ POST /api/daemon/heartbeat │ │
│ (with access token) │ │
├──────────────────────────► │ │
│ │ │
│ Heartbeat acknowledged │ │
│ ◄──────────────────────────┤ │
│ │ │Connecting from Neolith Web App
In your Neolith frontend:
import { io } from 'socket.io-client';
// Connect to orchestrator daemon
const socket = io('ws://localhost:8787', {
auth: {
token: 'your-jwt-token', // From Neolith API auth
},
});
socket.on('connect', () => {
console.log('Connected to orchestrator daemon');
// Spawn a session
socket.emit('spawn_session', {
orchestratorId: 'neolith-orchestrator',
task: {
id: 'task-1',
type: 'code',
description: 'Build React component',
priority: 'high',
},
});
});
// Listen for AI streaming responses
socket.on('stream_chunk', (chunk) => {
console.log('AI response:', chunk.data.chunk);
});
// Listen for task completion
socket.on('task_completed', (data) => {
console.log('Task completed:', data.taskId);
});API Client Usage
Use the built-in Neolith API client:
import { NeolithApiClient } from '@wundr.io/orchestrator-daemon/neolith';
const client = new NeolithApiClient({
baseUrl: process.env.NEOLITH_API_URL!,
apiKey: process.env.NEOLITH_API_KEY!,
apiSecret: process.env.NEOLITH_API_SECRET!,
});
// Authenticate
await client.authenticate(['messages:read', 'messages:write']);
// Send periodic heartbeats
setInterval(async () => {
await client.sendHeartbeat({
status: 'active',
metrics: {
memoryUsageMB: 256,
cpuUsagePercent: 15.5,
activeSessions: 5,
},
});
}, 30000);
// Send message to Neolith channel
await client.sendMessage('chan_123', 'Task completed successfully!');
// Get configuration
const config = await client.getConfig();
console.log('Orchestrator role:', config.orchestrator.role);Message Flow
When a user submits a task in Neolith:
- Neolith Web App sends task via REST API
- Neolith Server publishes to orchestrator via WebSocket
- Daemon receives task and spawns session
- Claude Code/Flow executes the task
- Daemon streams responses back to Neolith
- Neolith displays real-time progress to user
Development
Prerequisites
- Node.js 18+
- pnpm 8+
- TypeScript 5+
Setup
# Install dependencies
pnpm install
# Build the project
pnpm build
# Watch mode (auto-rebuild on changes)
pnpm devRunning Tests
# Run all tests
pnpm test
# Watch mode
pnpm test:watch
# With coverage
pnpm test -- --coverageType Checking
pnpm typecheckLinting & Formatting
# Lint
pnpm lint
# Format code
pnpm format
# Check formatting
pnpm format:checkBuilding
# Clean build
pnpm clean && pnpm build
# Build and watch
pnpm build:watchLocal Development with Hot Reload
# Start daemon in development mode
pnpm start:dev
# Or manually
NODE_ENV=development pnpm devTesting WebSocket Connections
Use wscat to test WebSocket connections:
# Install wscat
npm install -g wscat
# Connect to daemon
wscat -c ws://127.0.0.1:8787
# Send health check
> {"type":"health_check"}
# Spawn session
> {"type":"spawn_session","payload":{"orchestratorId":"test","task":{"id":"1","type":"code","description":"test task","priority":"high","status":"pending"}}}Debugging
Enable debug logging:
DEBUG=true DAEMON_VERBOSE=true pnpm startOr in code:
const daemon = new OrchestratorDaemon({
verbose: true,
// ... other config
});Contributing
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-feature - Make your changes
- Run tests:
pnpm test - Lint and format:
pnpm lint && pnpm format - Commit:
git commit -m "feat: add my feature" - Push:
git push origin feature/my-feature - Open a Pull Request
Troubleshooting
Common Issues
1. Port Already in Use
Error: EADDRINUSE: address already in use :::8787
Solution:
# Find process using port 8787
lsof -i :8787
# Kill the process
kill -9 <PID>
# Or use a different port
DAEMON_PORT=9090 orchestrator-daemon2. Redis Connection Failed
Error: Error connecting to Redis: ECONNREFUSED
Solution:
# Start Redis
redis-server
# Or via Docker
docker run -d -p 6379:6379 redis:7-alpine
# Or disable Redis features
unset REDIS_URL3. OpenAI API Key Not Set
Error: OpenAI API key is required
Solution:
# Set in environment
export OPENAI_API_KEY=sk-your-api-key
# Or in .env file
echo "OPENAI_API_KEY=sk-your-api-key" >> .env4. WebSocket Connection Timeout
Error: Client cannot connect to WebSocket
Solution:
- Check daemon is running:
curl http://127.0.0.1:8787/health - Check firewall settings
- Verify correct host/port in client
- Check daemon logs:
docker-compose logs daemon
5. Memory Issues
Error: JavaScript heap out of memory
Solution:
# Increase Node.js heap size
export NODE_OPTIONS="--max-old-space-size=4096"
# Or configure in .env
DAEMON_MAX_HEAP_MB=40966. Session Spawn Failures
Error: Failed to spawn session: Max sessions reached
Solution:
# Increase max sessions
DAEMON_MAX_SESSIONS=200 orchestrator-daemon
# Or stop idle sessions
curl -X POST http://127.0.0.1:8787/api/sessions/cleanup7. Token Budget Exceeded
Error: Token budget exceeded for period
Solution:
- Adjust budgets in
.env:TOKEN_BUDGET_DAILY=2000000 TOKEN_BUDGET_WEEKLY=10000000 - Monitor usage via metrics:
curl http://127.0.0.1:9090/metrics
8. Database Connection Issues
Error: Error connecting to database
Solution:
# Check PostgreSQL is running
docker-compose ps postgres
# View logs
docker-compose logs postgres
# Restart database
docker-compose restart postgresDebug Mode
Enable comprehensive debugging:
# Environment variables
export DEBUG=*
export LOG_LEVEL=debug
export DAEMON_VERBOSE=true
# Start daemon
orchestrator-daemonHealth Checks
# HTTP health check
curl http://127.0.0.1:8787/health
# Prometheus metrics (check all subsystems)
curl http://127.0.0.1:9090/metrics
# WebSocket health check (via wscat)
wscat -c ws://127.0.0.1:8787
> {"type":"health_check"}Logs
View daemon logs:
# Via Docker
docker-compose logs -f daemon
# Via systemd (if installed as service)
journalctl -u orchestrator-daemon -f
# Direct file logs (if LOG_FILE is set)
tail -f /var/log/orchestrator-daemon.logPerformance Issues
If experiencing slow performance:
Check resource usage:
curl http://127.0.0.1:9090/metrics | grep process_Reduce max sessions:
DAEMON_MAX_SESSIONS=50 orchestrator-daemonEnable memory compaction:
MEMORY_COMPACTION_ENABLED=true MEMORY_COMPACTION_THRESHOLD=0.7Use Redis for session caching:
REDIS_URL=redis://localhost:6379
Getting Help
- GitHub Issues: Report a bug
- Documentation: Full docs
- Community: Join our Discord
API Reference
Full TypeScript API documentation:
Main Classes
OrchestratorDaemon- Core daemon orchestratorOrchestratorWebSocketServer- WebSocket communication serverSessionManager- Session lifecycle managementMemoryManager- Three-tier memory systemNeolithApiClient- Neolith integration clientFederationCoordinator- Multi-daemon coordinationTokenTracker- Budget tracking and enforcement
See API documentation for detailed reference.
Features
Core Features
- ✅ WebSocket server with real-time bidirectional communication
- ✅ Multi-session orchestration (spawn, monitor, stop)
- ✅ Three-tier memory architecture (scratchpad/episodic/semantic)
- ✅ Charter-based governance and safety heuristics
- ✅ Resource limit enforcement
- ✅ Graceful shutdown and session cleanup
Distributed Features
- ✅ Federation across multiple daemon nodes
- ✅ Load balancing (round-robin, least-loaded, weighted, hash-based)
- ✅ Session migration between daemons
- ✅ Distributed state via Redis
- ✅ Cluster coordination and heartbeats
Monitoring & Observability
- ✅ Prometheus metrics endpoint
- ✅ Health check endpoint
- ✅ Real-time performance tracking
- ✅ Token budget monitoring and alerts
- ✅ Session lifecycle events
- ✅ Comprehensive logging (JSON/text, rotation)
Integration
- ✅ Neolith web app integration
- ✅ Claude Code session spawning
- ✅ Claude Flow orchestration
- ✅ Custom WebSocket clients
- ✅ REST API compatibility layer
Enterprise Features
- ✅ JWT authentication
- ✅ Rate limiting
- ✅ CORS support
- ✅ PostgreSQL persistent storage
- ✅ Redis caching and pub/sub
- ✅ Docker and Kubernetes ready
- ✅ Multi-environment configuration
Performance
Tested performance metrics (on 4-core, 8GB RAM machine):
- Max Concurrent Sessions: 100+
- WebSocket Connections: 1000+
- Message Throughput: 10,000 msgs/sec
- Memory Usage: ~256MB (idle), ~2GB (100 sessions)
- CPU Usage: ~5% (idle), ~40% (100 sessions)
- Startup Time: ~2 seconds
- Shutdown Time: ~5 seconds (graceful)
Roadmap
- [ ] gRPC support for high-performance RPC
- [ ] GraphQL API layer
- [ ] Multi-LLM provider support (Azure, Cohere, etc.)
- [ ] Advanced session scheduling and prioritization
- [ ] Distributed tracing (OpenTelemetry)
- [ ] Web UI for daemon management
- [ ] Kubernetes operator
- [ ] Auto-scaling based on load
License
MIT - see LICENSE for details
Author
Wundr, by Adaptic.ai
- Website: https://wundr.io
- GitHub: https://github.com/adapticai/wundr
- Issues: https://github.com/adapticai/wundr/issues
Acknowledgments
- Inspired by MemGPT memory architecture
- Built on ws WebSocket library
- Monitoring via prom-client
- Powered by OpenAI and Anthropic APIs
Made with ❤️ by the Wundr team
