<!--
hoody-daemon Subskill (http)
Auto-generated by Hoody Skills Generator
Generated: 2026-05-06T18:56:39.710Z
Model: mimo-v2.5-pro + fixer:mimo-v2.5-pro
Mode: http


Tokens: 9901

DO NOT EDIT MANUALLY - Changes will be overwritten on next generation
-->

# hoody-daemon Subskill

## Overview

### What is hoody-daemon?

hoody-daemon is a long-running service management system that provides HTTP-based control over background processes within Hoody Kit containers. It wraps supervisord to offer programmatic control over daemon processes, enabling you to start, stop, monitor, and manage persistent services without SSH access.

### When to Use hoody-daemon

Use hoody-daemon when you need to:

- **Run background services**: Web servers, queue workers, WebSocket handlers, or any long-running process
- **Manage application daemons**: Start/stop/restart your custom application processes
- **Monitor process health**: Check if services are running and retrieve their logs
- **Run ephemeral tasks**: Execute temporary processes that auto-cleanup when stopped
- **Control system services**: Manage pre-configured services like Apache, Nginx, or Redis

### How It Fits Into Hoody Philosophy

hoody-daemon embodies Hoody's service management philosophy:

- **HTTP-first control**: All operations via REST API—no SSH required
- **Declarative configuration**: Define programs as JSON, daemon manages the lifecycle
- **Automatic cleanup**: Ephemeral programs clean up on stop or container reboot
- **Isolation**: Each program runs in its own supervisord-managed process
- **Observability**: Built-in status monitoring and log retrieval

### Service Architecture

```
┌─────────────────────────────────────────────────────────┐
│                    hoody-daemon                          │
├─────────────────────────────────────────────────────────┤
│  HTTP API Layer                                         │
│  ├── /api/v1/daemon/programs/*  (persistent programs)   │
│  ├── /api/v1/daemon/quick-start/* (ephemeral programs)  │
│  ├── /api/v1/daemon/status/*    (runtime monitoring)    │
│  └── /api/v1/daemon/health      (service health)        │
├─────────────────────────────────────────────────────────┤
│  supervisord Integration                                │
│  ├── Process spawning & management                      │
│  ├── Auto-restart on failure                            │
│  └── Log file management                                │
└─────────────────────────────────────────────────────────┘
```

### Base URL Pattern

All hoody-daemon endpoints use this base URL:

```
https://{projectId}-{containerId}-daemon-{serviceId}.{node}.containers.hoody.icu
```

**Example:**
```
https://proj123-container456-daemon-daemon01.us-east-1.containers.hoody.icu
```

---

## Common Workflows

### Workflow 1: Health Check & Service Discovery

**Purpose**: Verify daemon service is operational and discover available programs.

**Step 1: Check daemon health**

```
# Unauthenticated health check
curl -s "https://{projectId}-{containerId}-daemon-{serviceId}.{node}.containers.hoody.icu/api/v1/daemon/health"
```

**Expected Response:**
```
{
  "status": "healthy",
  "service": "hoody-daemon",
  "version": "1.0.0",
  "timestamp": "2025-01-15T10:30:00Z",
  "uptime": 86400,
  "checks": {
    "supervisord": "connected",
    "config": "valid"
  }
}
```

**Step 2: List all configured programs**

```
curl -s "https://{projectId}-{containerId}-daemon-{serviceId}.{node}.containers.hoody.icu/api/v1/daemon/programs"
```

**Expected Response:**
```
[
  {
    "id": "web-server",
    "name": "Web Server",
    "command": "node server.js",
    "user": "app",
    "enabled": true,
    "hoody_kit": true,
    "port_range": {
      "start": 3000,
      "end": 3000
    }
  }
]
```

**Step 3: Get detailed status of all programs**

```
curl -s "https://{projectId}-{containerId}-daemon-{serviceId}.{node}.containers.hoody.icu/api/v1/daemon/status"
```

**Expected Response:**
```
[
  {
    "id": "web-server",
    "name": "Web Server",
    "status": "RUNNING",
    "pid": 12345,
    "uptime": 3600,
    "exit_status": 0
  }
]
```

---

### Workflow 2: Add and Start a Custom Program

**Purpose**: Register a new background service and start it.

**Step 1: Add a new program**

```
curl -s -X POST \
  "https://{projectId}-{containerId}-daemon-{serviceId}.{node}.containers.hoody.icu/api/v1/daemon/programs/add" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "queue-worker",
    "command": "php artisan queue:work --sleep=3 --tries=3",
    "user": "app",
    "port_range": {
      "start": 0,
      "end": 0
    }
  }'
```

**Expected Response:**
```
{
  "success": true,
  "message": "Program added successfully",
  "program": {
    "id": "queue-worker",
    "name": "queue-worker",
    "command": "php artisan queue:work --sleep=3 --tries=3",
    "user": "app",
    "enabled": true,
    "port_range": {
      "start": 0,
      "end": 0
    }
  }
}
```

**Step 2: Start the program**

```
curl -s -X POST \
  "https://{projectId}-{containerId}-daemon-{serviceId}.{node}.containers.hoody.icu/api/v1/daemon/programs/queue-worker/start"
```

**Expected Response:**
```
{
  "success": true,
  "message": "Program started",
  "status": "RUNNING",
  "pid": 12346
}
```

**Step 3: Verify it's running**

```
curl -s \
  "https://{projectId}-{containerId}-daemon-{serviceId}.{node}.containers.hoody.icu/api/v1/daemon/status/queue-worker"
```

**Expected Response:**
```
{
  "id": "queue-worker",
  "name": "queue-worker",
  "status": "RUNNING",
  "pid": 12346,
  "uptime": 5,
  "exit_status": 0
}
```

**Step 4: Check program logs**

```
curl -s \
  "https://{projectId}-{containerId}-daemon-{serviceId}.{node}.containers.hoody.icu/api/v1/daemon/programs/queue-worker/logs"
```

**Expected Response:**
```
{
  "stdout": "[2025-01-15 10:30:00] Processing: job-123\n[2025-01-15 10:30:01] Completed: job-123",
  "stderr": ""
}
```

---

### Workflow 3: Quick Start Ephemeral Programs

**Purpose**: Run a temporary process that auto-cleans when stopped.

**Step 1: Start an ephemeral program**

```
curl -s -X POST \
  "https://{projectId}-{containerId}-daemon-{serviceId}.{node}.containers.hoody.icu/api/v1/daemon/quick-start" \
  -H "Content-Type: application/json" \
  -d '{
    "command": "python3 /app/scripts/data-migration.py --batch=1000",
    "user": "app"
  }'
```

**Expected Response:**
```
{
  "success": true,
  "temporary_id": "eph-abc123def456",
  "message": "Ephemeral program started",
  "status": "RUNNING"
}
```

**Step 2: Check ephemeral program status**

```
curl -s \
  "https://{projectId}-{containerId}-daemon-{serviceId}.{node}.containers.hoody.icu/api/v1/daemon/quick-start/eph-abc123def456/status"
```

**Expected Response:**
```
{
  "temporary_id": "eph-abc123def456",
  "command": "python3 /app/scripts/data-migration.py --batch=1000",
  "status": "RUNNING",
  "pid": 12347,
  "uptime": 120
}
```

**Step 3: View ephemeral program logs**

```
curl -s \
  "https://{projectId}-{containerId}-daemon-{serviceId}.{node}.containers.hoody.icu/api/v1/daemon/quick-start/eph-abc123def456/logs"
```

**Expected Response:**
```
{
  "stdout": "Processing batch 1/10...\nProcessing batch 2/10...\n",
  "stderr": ""
}
```

**Step 4: Stop and cleanup ephemeral program**

```
curl -s -X POST \
  "https://{projectId}-{containerId}-daemon-{serviceId}.{node}.containers.hoody.icu/api/v1/daemon/quick-start/eph-abc123def456/stop"
```

**Expected Response:**
```
{
  "success": true,
  "message": "Ephemeral program stopped and removed",
  "actions_performed": [
    "stopped via supervisorctl",
    "deleted supervisord config",
    "removed from ephemeral.json"
  ]
}
```

---

### Workflow 4: Program Lifecycle Management

**Purpose**: Enable, disable, edit, and remove programs.

**Step 1: Disable a program (stops if running)**

```
curl -s -X POST \
  "https://{projectId}-{containerId}-daemon-{serviceId}.{node}.containers.hoody.icu/api/v1/daemon/programs/queue-worker/disable"
```

**Expected Response:**
```
{
  "success": true,
  "message": "Program disabled",
  "was_running": true,
  "actions": ["stopped", "removed from supervisord"]
}
```

**Step 2: Edit program configuration**

```
curl -s -X POST \
  "https://{projectId}-{containerId}-daemon-{serviceId}.{node}.containers.hoody.icu/api/v1/daemon/programs/edit/queue-worker" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "queue-worker",
    "command": "php artisan queue:work --sleep=5 --tries=5 --max-time=3600",
    "user": "app",
    "port_range": {
      "start": 0,
      "end": 0
    }
  }'
```

**Expected Response:**
```
{
  "success": true,
  "message": "Program updated",
  "program": {
    "id": "queue-worker",
    "name": "queue-worker",
    "command": "php artisan queue:work --sleep=5 --tries=5 --max-time=3600",
    "user": "app",
    "enabled": false,
    "port_range": {
      "start": 0,
      "end": 0
    }
  }
}
```

**Step 3: Re-enable the program**

```
curl -s -X POST \
  "https://{projectId}-{containerId}-daemon-{serviceId}.{node}.containers.hoody.icu/api/v1/daemon/programs/queue-worker/enable"
```

**Expected Response:**
```
{
  "success": true,
  "message": "Program enabled and registered with supervisord"
}
```

**Step 4: Remove a program permanently**

```
curl -s -X POST \
  "https://{projectId}-{containerId}-daemon-{serviceId}.{node}.containers.hoody.icu/api/v1/daemon/programs/remove/queue-worker"
```

**Expected Response:**
```
{
  "success": true,
  "message": "Program removed permanently",
  "was_running": false
}
```

---

## Advanced Operations

### Advanced Workflow 1: Port-Range Programs (Multi-Instance)

**Purpose**: Run multiple instances of a service across a port range.

**Step 1: Add a port-range program**

```
curl -s -X POST \
  "https://{projectId}-{containerId}-daemon-{serviceId}.{node}.containers.hoody.icu/api/v1/daemon/programs/add" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "api-worker",
    "command": "node /app/server.js --port={{PORT}}",
    "user": "app",
    "port_range": {
      "start": 3001,
      "end": 3010
    }
  }'
```

**Expected Response:**
```
{
  "success": true,
  "message": "Program added successfully",
  "program": {
    "id": "api-worker",
    "name": "api-worker",
    "command": "node /app/server.js --port={{PORT}}",
    "user": "app",
    "enabled": true,
    "port_range": {
      "start": 3001,
      "end": 3010
    }
  }
}
```

**Step 2: Start a specific port instance**

```
curl -s -X POST \
  "https://{projectId}-{containerId}-daemon-{serviceId}.{node}.containers.hoody.icu/api/v1/daemon/programs/api-worker/start" \
  -H "Content-Type: application/json" \
  -d '{
    "port": 3001
  }'
```

**Expected Response:**
```
{
  "success": true,
  "message": "Program instance started",
  "port": 3001,
  "status": "RUNNING",
  "pid": 12350
}
```

**Step 3: Check status of all instances**

```
curl -s \
  "https://{projectId}-{containerId}-daemon-{serviceId}.{node}.containers.hoody.icu/api/v1/daemon/status/api-worker"
```

**Expected Response:**
```
{
  "id": "api-worker",
  "name": "api-worker",
  "instances": [
    {
      "port": 3001,
      "status": "RUNNING",
      "pid": 12350,
      "uptime": 60
    },
    {
      "port": 3002,
      "status": "STOPPED",
      "pid": null,
      "uptime": 0
    }
  ]
}
```

**Step 4: Stop all instances at once**

```
curl -s -X POST \
  "https://{projectId}-{containerId}-daemon-{serviceId}.{node}.containers.hoody.icu/api/v1/daemon/programs/api-worker/stop" \
  -H "Content-Type: application/json" \
  -d '{
    "all": true
  }'
```

**Expected Response:**
```
{
  "success": true,
  "message": "All instances stopped",
  "stopped_ports": [3001, 3002, 3003]
}
```

---

### Advanced Workflow 2: Reset to Default Configuration

**Purpose**: Restore daemon to initial state, removing all custom programs.

**Step 1: Reset programs to defaults**

```
curl -s -X POST \
  "https://{projectId}-{containerId}-daemon-{serviceId}.{node}.containers.hoody.icu/api/v1/daemon/programs/reset"
```

**Expected Response:**
```
{
  "success": true,
  "message": "Programs reset to defaults",
  "actions_performed": [
    "stopped all managed programs",
    "removed supervisord configs",
    "applied programs.default.json"
  ],
  "programs_count": 5
}
```

**Step 2: Verify reset completed**

```
curl -s \
  "https://{projectId}-{containerId}-daemon-{serviceId}.{node}.containers.hoody.icu/api/v1/daemon/programs"
```

**Expected Response:**
```
[
  {
    "id": "apache2",
    "name": "Apache2",
    "command": "/usr/sbin/apache2ctl -D FOREGROUND",
    "user": "root",
    "enabled": true,
    "hoody_kit": true,
    "port_range": {
      "start": 0,
      "end": 0
    }
  }
]
```

---

### Advanced Workflow 3: Error Recovery Pattern

**Purpose**: Handle failed programs and recover gracefully.

**Step 1: Identify failed programs**

```
curl -s \
  "https://{projectId}-{containerId}-daemon-{serviceId}.{node}.containers.hoody.icu/api/v1/daemon/status"
```

**Expected Response (with failure):**
```
[
  {
    "id": "web-server",
    "name": "Web Server",
    "status": "FATAL",
    "pid": null,
    "exit_status": 1,
    "spawn_error": "Failed to start: port 3000 already in use"
  }
]
```

**Step 2: Check logs to diagnose**

```
curl -s \
  "https://{projectId}-{containerId}-daemon-{serviceId}.{node}.containers.hoody.icu/api/v1/daemon/programs/web-server/logs"
```

**Expected Response:**
```
{
  "stdout": "",
  "stderr": "Error: listen EADDRINUSE: address already in use 0.0.0.0:3000\n    at Server.setupListenHandle [as _listen2] (net.js:1314:16)"
}
```

**Step 3: Stop the failed program**

```
curl -s -X POST \
  "https://{projectId}-{containerId}-daemon-{serviceId}.{node}.containers.hoody.icu/api/v1/daemon/programs/web-server/stop"
```

**Expected Response:**
```
{
  "success": true,
  "message": "Program stopped"
}
```

**Step 4: Edit to fix the issue**

```
curl -s -X POST \
  "https://{projectId}-{containerId}-daemon-{serviceId}.{node}.containers.hoody.icu/api/v1/daemon/programs/edit/web-server" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "web-server",
    "command": "node server.js --port=3001",
    "user": "app",
    "port_range": {
      "start": 3001,
      "end": 3001
    }
  }'
```

**Expected Response:**
```
{
  "success": true,
  "message": "Program updated",
  "program": {
    "id": "web-server",
    "name": "web-server",
    "command": "node server.js --port=3001",
    "user": "app",
    "enabled": true,
    "port_range": {
      "start": 3001,
      "end": 3001
    }
  }
}
```

**Step 5: Restart the program**

```
curl -s -X POST \
  "https://{projectId}-{containerId}-daemon-{serviceId}.{node}.containers.hoody.icu/api/v1/daemon/programs/web-server/start"
```

**Expected Response:**
```
{
  "success": true,
  "message": "Program started",
  "status": "RUNNING",
  "pid": 12355
}
```

---

### Performance Considerations

**Log Retrieval Limits:**
- Default log retrieval returns last 100 lines
- Use query parameter `lines=N` to retrieve more: `?lines=500`
- Large log files may increase response time

**Port Range Limits:**
- Maximum port range: 1000 ports per program
- Each port instance consumes memory and file descriptors
- Monitor system resources when running many instances

**Ephemeral Program Cleanup:**
- Ephemeral programs auto-cleanup on container reboot
- Manual stop triggers immediate cleanup
- Pending cleanup programs appear in quick-start list

**Status Polling:**
- Status endpoint is lightweight and safe to poll frequently
- Use exponential backoff for long-running operations
- Check logs for detailed progress information

---

## Quick Reference

### Most Common Endpoints

| Operation | Method | Endpoint |
|-----------|--------|----------|
| Health check | GET | `/api/v1/daemon/health` |
| List programs | GET | `/api/v1/daemon/programs` |
| Get program details | GET | `/api/v1/daemon/programs/{id}` |
| Add program | POST | `/api/v1/daemon/programs/add` |
| Start program | POST | `/api/v1/daemon/programs/{id}/start` |
| Stop program | POST | `/api/v1/daemon/programs/{id}/stop` |
| Get all status | GET | `/api/v1/daemon/status` |
| Get program status | GET | `/api/v1/daemon/status/{id}` |
| Get program logs | GET | `/api/v1/daemon/programs/{id}/logs` |
| Quick start | POST | `/api/v1/daemon/quick-start` |
| Stop ephemeral | POST | `/api/v1/daemon/quick-start/{id}/stop` |





### Program Status Values

| Status | Description |
|--------|-------------|
| `RUNNING` | Process is active and healthy |
| `STOPPED` | Process is stopped (expected) |
| `STARTING` | Process is starting up |
| `STOPPING` | Process is shutting down |
| `FATAL` | Process failed to start or crashed |
| `UNKNOWN` | Status cannot be determined |

### Error Response Format

```
{
  "success": false,
  "error": "Error description",
  "code": "ERROR_CODE"
}
```

### Common Error Codes

| Code | Description |
|------|-------------|
| `PROGRAM_NOT_FOUND` | Program ID doesn't exist |
| `PROGRAM_ALREADY_EXISTS` | Duplicate program name |
| `INVALID_PORT_RANGE` | Port range exceeds 1000 or invalid |
| `USER_NOT_FOUND` | System user doesn't exist |
| `SUPERVISORD_ERROR` | supervisord communication failure |
| `PROGRAM_RUNNING` | Cannot modify running program |

---

