Skip to content

Daemon Management

The Daemon Management module provides cross-platform service generation and lifecycle management.

Overview

This module enables AIV agents to run as system services on:

  • Linux - systemd unit files
  • macOS - launchd plist files
  • Windows - (planned)

Features

  • 🔧 Automatic service file generation
  • 🔄 Auto-restart on failure
  • 📊 Resource limits (memory, CPU)
  • 🔐 Security hardening options
  • 📁 Working directory management
  • 🌐 Environment variable support

Installation

typescript
import {
  DaemonManager,
  createDaemonManager,
  DaemonConfig,
} from '@aiversum/aiv-agents/daemon';

Basic Usage

Creating a Daemon Manager

typescript
const daemon = createDaemonManager({
  name: 'aiv-soc-agent',
  description: 'AIV SOC Security Agent',
  command: '/usr/bin/node',
  args: ['dist/agent.js'],
  workingDirectory: '/opt/aiv/agents/soc',
  user: 'aiv',
  group: 'aiv',
});

Generating Service Files

typescript
// Get the unit file content
const unitContent = daemon.generateUnit();
console.log(unitContent);

// Output for systemd:
// [Unit]
// Description=AIV SOC Security Agent
// After=network.target
//
// [Service]
// Type=simple
// User=aiv
// Group=aiv
// WorkingDirectory=/opt/aiv/agents/soc
// ExecStart=/usr/bin/node dist/agent.js
// Restart=always
// RestartSec=10
//
// [Install]
// WantedBy=multi-user.target

Installing the Service

typescript
// Install to system (requires elevated permissions)
await daemon.install();

// Or get the install path
const path = daemon.getInstallPath();
// Linux: /etc/systemd/system/aiv-soc-agent.service
// macOS: ~/Library/LaunchAgents/ai.aiversum.aiv-soc-agent.plist

Configuration

Full Configuration Options

typescript
interface DaemonConfig {
  // Required
  name: string;              // Service name (alphanumeric + hyphens)
  description: string;       // Human-readable description
  command: string;           // Executable path

  // Optional
  args?: string[];           // Command arguments
  workingDirectory?: string; // Working directory
  user?: string;             // Run as user
  group?: string;            // Run as group

  // Restart behavior
  restart?: 'always' | 'on-failure' | 'no';
  restartDelay?: number;     // Seconds between restarts

  // Resource limits
  memoryLimit?: string;      // e.g., '512M', '2G'
  cpuQuota?: number;         // Percentage (0-100)

  // Environment
  environment?: Record<string, string>;
  environmentFile?: string;  // Path to env file

  // Logging
  logPath?: string;          // Custom log path
  logLevel?: 'debug' | 'info' | 'warn' | 'error';

  // Security (systemd only)
  sandbox?: boolean;         // Enable sandboxing
  noNewPrivileges?: boolean; // Prevent privilege escalation
}

Example: High-Security Configuration

typescript
const secureAgent = createDaemonManager({
  name: 'aiv-secure-agent',
  description: 'Hardened AIV Agent',
  command: '/usr/bin/node',
  args: ['agent.js'],
  workingDirectory: '/opt/aiv/secure',

  // Run as dedicated user
  user: 'aiv-secure',
  group: 'aiv-secure',

  // Resource limits
  memoryLimit: '1G',
  cpuQuota: 50,

  // Auto-restart
  restart: 'on-failure',
  restartDelay: 30,

  // Security hardening
  sandbox: true,
  noNewPrivileges: true,

  // Environment
  environment: {
    NODE_ENV: 'production',
    LOG_LEVEL: 'info',
  },
});

Platform-Specific Features

systemd (Linux)

The module generates compliant systemd unit files with:

ini
[Unit]
Description=AIV Agent
After=network.target
Wants=network-online.target

[Service]
Type=simple
User=aiv
Group=aiv
WorkingDirectory=/opt/aiv

# Command
ExecStart=/usr/bin/node agent.js

# Restart policy
Restart=always
RestartSec=10

# Resource limits
MemoryLimit=1G
CPUQuota=50%

# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true

# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=aiv-agent

[Install]
WantedBy=multi-user.target

launchd (macOS)

Generates compliant plist files:

xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>ai.aiversum.aiv-agent</string>

    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/node</string>
        <string>agent.js</string>
    </array>

    <key>WorkingDirectory</key>
    <string>/opt/aiv</string>

    <key>RunAtLoad</key>
    <true/>

    <key>KeepAlive</key>
    <true/>

    <key>StandardOutPath</key>
    <string>/var/log/aiv/agent.log</string>

    <key>StandardErrorPath</key>
    <string>/var/log/aiv/agent.error.log</string>
</dict>
</plist>

Service Lifecycle

Start/Stop/Restart

typescript
// Start the service
await daemon.start();

// Stop the service
await daemon.stop();

// Restart the service
await daemon.restart();

// Check status
const status = await daemon.status();
console.log(status); // 'running' | 'stopped' | 'failed'

Uninstall

typescript
// Remove the service
await daemon.uninstall();

Events

The daemon manager emits events:

typescript
daemon.on('install', ({ path }) => {
  console.log(`Service installed at ${path}`);
});

daemon.on('start', () => {
  console.log('Service started');
});

daemon.on('stop', ({ reason }) => {
  console.log(`Service stopped: ${reason}`);
});

daemon.on('error', ({ error }) => {
  console.error('Service error:', error);
});

Security Considerations

Permissions

  • Service files are created with 0o644 permissions
  • Environment files should be 0o600
  • Working directories should be owned by the service user

User Isolation

Always run services as dedicated non-root users:

bash
# Create dedicated user
sudo useradd -r -s /bin/false aiv-agent

# Set ownership
sudo chown -R aiv-agent:aiv-agent /opt/aiv/agent

Sandboxing (systemd)

Enable sandboxing for maximum isolation:

typescript
const sandboxed = createDaemonManager({
  // ...
  sandbox: true,
  noNewPrivileges: true,
});

This adds protections:

  • ProtectSystem=strict - Read-only /usr, /boot, /etc
  • ProtectHome=true - No access to /home
  • PrivateTmp=true - Isolated /tmp
  • NoNewPrivileges=true - Cannot gain privileges

API Reference

See the DaemonManager API Reference for complete documentation.

Testing

bash
# Run daemon module tests
npm test -- --grep "daemon"

# Test count: 99 tests

Released under the MIT License.