npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@wundr.io/orchestrator-daemon

v1.0.6

Published

Orchestrator Daemon for agent orchestration and session management

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.

Version Node License

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-daemon

Configuration

  1. Copy the example environment file:
cp .env.example .env
  1. Edit .env and 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_here

Running 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.json

Option 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 stop

Option 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.sh

You 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 -d

2. View logs:

# All services
docker-compose logs -f

# Daemon only
docker-compose logs -f daemon

3. Check status:

docker-compose ps

4. Stop services:

docker-compose down

5. Stop and remove volumes (clean slate):

docker-compose down -v

Development 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:dev

Environment 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=60000

Custom 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-daemon

Health 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-daemon

Integration 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_here

2. 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:

  1. Neolith Web App sends task via REST API
  2. Neolith Server publishes to orchestrator via WebSocket
  3. Daemon receives task and spawns session
  4. Claude Code/Flow executes the task
  5. Daemon streams responses back to Neolith
  6. 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 dev

Running Tests

# Run all tests
pnpm test

# Watch mode
pnpm test:watch

# With coverage
pnpm test -- --coverage

Type Checking

pnpm typecheck

Linting & Formatting

# Lint
pnpm lint

# Format code
pnpm format

# Check formatting
pnpm format:check

Building

# Clean build
pnpm clean && pnpm build

# Build and watch
pnpm build:watch

Local Development with Hot Reload

# Start daemon in development mode
pnpm start:dev

# Or manually
NODE_ENV=development pnpm dev

Testing 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 start

Or in code:

const daemon = new OrchestratorDaemon({
  verbose: true,
  // ... other config
});

Contributing

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/my-feature
  3. Make your changes
  4. Run tests: pnpm test
  5. Lint and format: pnpm lint && pnpm format
  6. Commit: git commit -m "feat: add my feature"
  7. Push: git push origin feature/my-feature
  8. 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-daemon

2. 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_URL

3. 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" >> .env

4. 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=4096

6. 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/cleanup

7. 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 postgres

Debug Mode

Enable comprehensive debugging:

# Environment variables
export DEBUG=*
export LOG_LEVEL=debug
export DAEMON_VERBOSE=true

# Start daemon
orchestrator-daemon

Health 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.log

Performance Issues

If experiencing slow performance:

  1. Check resource usage:

    curl http://127.0.0.1:9090/metrics | grep process_
  2. Reduce max sessions:

    DAEMON_MAX_SESSIONS=50 orchestrator-daemon
  3. Enable memory compaction:

    MEMORY_COMPACTION_ENABLED=true
    MEMORY_COMPACTION_THRESHOLD=0.7
  4. Use Redis for session caching:

    REDIS_URL=redis://localhost:6379

Getting Help

API Reference

Full TypeScript API documentation:

Main Classes

  • OrchestratorDaemon - Core daemon orchestrator
  • OrchestratorWebSocketServer - WebSocket communication server
  • SessionManager - Session lifecycle management
  • MemoryManager - Three-tier memory system
  • NeolithApiClient - Neolith integration client
  • FederationCoordinator - Multi-daemon coordination
  • TokenTracker - 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