<!--
hoody-daemon Subskill (cli)
Auto-generated by Hoody Skills Generator
Generated: 2026-05-06T20:54:50.743Z
Model: mimo-v2.5-pro + fixer:mimo-v2.5-pro
Mode: cli


Tokens: 10507

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

# hoody-daemon Subskill

## Overview

### Purpose

hoody-daemon manages long-running processes and services within Hoody containers. It provides lifecycle control for persistent programs, ephemeral tasks, and system services through supervisor-based process management.

### When to Use

- **Custom applications**: Your Node.js, Python, or Go services that need to run continuously
- **Background workers**: Queue processors, cron-like tasks, or monitoring agents
- **Development servers**: Hot-reload dev servers for testing
- **Ephemeral tasks**: One-off scripts or temporary services that auto-cleanup
- **Port-range services**: Applications that spawn multiple instances across port ranges

### Philosophy Alignment

hoody-daemon embodies Hoody's service management philosophy:

- **Declarative configuration**: Define programs once, manage them consistently
- **Observable state**: Always know what's running and why
- **Clean lifecycle**: Proper startup, shutdown, and cleanup sequences
- **Isolation**: Each program runs independently with its own logs and status

### Architecture

The architecture is layered: the hoody daemon CLI interfaces with the Daemon HTTP API, which manages Program Configuration (programs.json and ephemeral.json). Supervisord runs the programs, which can be single-instance or port-range with multiple instances.

### Program Types

| Type | Description | Lifecycle |
|------|-------------|-----------|
| **Custom** | User-defined programs with explicit configuration | Persistent until removed |
| **System** | Pre-configured services (apache2, nginx, etc.) | Managed via systemctl |
| **Ephemeral** | Temporary programs via quick-start | Auto-cleanup on stop/reboot |
| **Port-range** | Programs spawning multiple instances | Each instance on separate port |

### Container Targeting

All daemon commands require a container context:

```
# Via flag
hoody daemon list -c my-container-id

# Via environment variable
export HOODY_CONTAINER=my-container-id
hoody daemon list
```

---

## Common Workflows

### Workflow 1: Health Check and Service Discovery

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

```
# Step 1: Check daemon health
hoody daemon health -c my-container
```

```
{
  "status": "healthy",
  "service": "hoody-daemon",
  "version": "1.0.0",
  "timestamp": "2025-11-05T10:30:00Z",
  "uptime": 86400,
  "dependencies": {
    "supervisord": "running",
    "filesystem": "accessible"
  },
  "metrics": {
    "programs_total": 5,
    "programs_running": 3
  },
  "checks": {
    "config_valid": true,
    "supervisor_connected": true
  }
}
```

```
# Step 2: List all configured programs
hoody daemon list -c my-container
```

```
[
  {
    "id": "web-server",
    "name": "Web Server",
    "command": "node /app/server.js",
    "user": "app",
    "enabled": true,
    "hoody_kit": false,
    "lazy_load": false,
    "boot": true,
    "port_range": null,
    "environment": {
      "NODE_ENV": "production"
    },
    "created_at": "2025-11-01T00:00:00Z",
    "updated_at": "2025-11-05T10:00:00Z"
  },
  {
    "id": "worker",
    "name": "Background Worker",
    "command": "python /app/worker.py",
    "user": "app",
    "enabled": true,
    "hoody_kit": false,
    "lazy_load": true,
    "boot": false,
    "port_range": null,
    "environment": {},
    "created_at": "2025-11-01T00:00:00Z",
    "updated_at": "2025-11-01T00:00:00Z"
  }
]
```

```
# Step 3: Get detailed status for all programs
hoody daemon statuses -c my-container
```

```
[
  {
    "id": "web-server",
    "name": "Web Server",
    "status": "running",
    "pid": 1234,
    "uptime": 3600,
    "exit_code": null,
    "restart_count": 0,
    "last_start": "2025-11-05T09:30:00Z",
    "last_stop": null,
    "port": null
  },
  {
    "id": "worker",
    "name": "Background Worker",
    "status": "stopped",
    "pid": null,
    "uptime": null,
    "exit_code": 0,
    "restart_count": 0,
    "last_start": null,
    "last_stop": null,
    "port": null
  }
]
```

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

**Scenario**: Deploy a new Node.js application as a managed daemon.

```
# Step 1: Create the program configuration
hoody daemon create -c my-container
```

When prompted interactively or via JSON input (piped to stdin):

```
{
  "name": "API Server",
  "command": "node /app/api/server.js --port 3000",
  "user": "app",
  "port_range": null,
  "environment": {
    "NODE_ENV": "production",
    "API_KEY": "secret-key"
  },
  "auto_restart": true,
  "start_retries": 3,
  "stop_wait_secs": 10
}
```

```
# Step 2: Verify program was created
hoody daemon get api-server -c my-container
```

```
{
  "id": "api-server",
  "name": "API Server",
  "command": "node /app/api/server.js --port 3000",
  "user": "app",
  "enabled": true,
  "hoody_kit": false,
  "lazy_load": false,
  "boot": true,
  "port_range": null,
  "environment": {
    "NODE_ENV": "production",
    "API_KEY": "secret-key"
  },
  "auto_restart": true,
  "start_retries": 3,
  "stop_wait_secs": 10,
  "created_at": "2025-11-05T10:30:00Z",
  "updated_at": "2025-11-05T10:30:00Z"
}
```

```
# Step 3: Start the program
hoody daemon start api-server -c my-container
```

```
# Step 4: Verify it's running
hoody daemon status api-server -c my-container
```

```
{
  "id": "api-server",
  "name": "API Server",
  "status": "running",
  "pid": 5678,
  "uptime": 5,
  "exit_code": null,
  "restart_count": 0,
  "last_start": "2025-11-05T10:31:00Z",
  "last_stop": null,
  "port": null
}
```

```
# Step 5: Check application logs
hoody daemon logs api-server -c my-container
```

```
{
  "program_id": "api-server",
  "log_type": "stdout",
  "lines": 100,
  "content": "[2025-11-05T10:31:00Z] INFO: Server starting on port 3000\n[2025-11-05T10:31:01Z] INFO: Connected to database\n[2025-11-05T10:31:01Z] INFO: Server ready"
}
```

### Workflow 3: Manage Program Lifecycle

**Scenario**: Stop, edit, and restart a program with updated configuration.

```
# Step 1: Stop the running program
hoody daemon stop api-server -c my-container
```

```
# Step 2: Verify it stopped
hoody daemon status api-server -c my-container
```

```
{
  "id": "api-server",
  "name": "API Server",
  "status": "stopped",
  "pid": null,
  "uptime": null,
  "exit_code": 0,
  "restart_count": 0,
  "last_start": "2025-11-05T10:31:00Z",
  "last_stop": "2025-11-05T11:00:00Z",
  "port": null
}
```

```
# Step 3: Edit the program configuration
hoody daemon edit api-server -c my-container
```

Update specific fields:

```
{
  "command": "node /app/api/server.js --port 3000 --workers 4",
  "environment": {
    "NODE_ENV": "production",
    "API_KEY": "new-secret-key",
    "WORKERS": "4"
  }
}
```

```
# Step 4: Verify configuration updated
hoody daemon get api-server -c my-container
```

```
{
  "id": "api-server",
  "name": "API Server",
  "command": "node /app/api/server.js --port 3000 --workers 4",
  "user": "app",
  "enabled": true,
  "hoody_kit": false,
  "lazy_load": false,
  "boot": true,
  "port_range": null,
  "environment": {
    "NODE_ENV": "production",
    "API_KEY": "new-secret-key",
    "WORKERS": "4"
  },
  "auto_restart": true,
  "start_retries": 3,
  "stop_wait_secs": 10,
  "created_at": "2025-11-05T10:30:00Z",
  "updated_at": "2025-11-05T11:05:00Z"
}
```

```
# Step 5: Restart with new configuration
hoody daemon start api-server -c my-container
```

### Workflow 4: Ephemeral Programs (Quick Start)

**Scenario**: Run a temporary script that auto-cleans when done.

```
# Step 1: Launch an ephemeral program
hoody daemon start -c my-container
```

Provide the ephemeral program details:

```
{
  "command": "python /scripts/data-migration.py --batch-size 1000",
  "user": "app",
  "environment": {
    "DATABASE_URL": "postgres://localhost/mydb"
  }
}
```

```
# Step 2: List all ephemeral programs
hoody daemon list -c my-container

Note: This command lists only ephemeral programs. To list persistent programs, use `hoody daemon list` without the ephemeral context, or use filters to distinguish them.
```

```
[
  {
    "id": "ephemeral-abc123",
    "command": "python /scripts/data-migration.py --batch-size 1000",
    "user": "app",
    "status": "running",
    "pid": 9012,
    "started_at": "2025-11-05T11:00:00Z",
    "auto_cleanup": true
  }
]
```

```
# Step 3: Check ephemeral program status
hoody daemon status ephemeral-abc123 -c my-container
```

```
{
  "id": "ephemeral-abc123",
  "command": "python /scripts/data-migration.py --batch-size 1000",
  "user": "app",
  "status": "running",
  "pid": 9012,
  "uptime": 120,
  "exit_code": null,
  "started_at": "2025-11-05T11:00:00Z"
}
```

```
# Step 4: View ephemeral program logs
hoody daemon logs ephemeral-abc123 -c my-container
```

```
{
  "program_id": "ephemeral-abc123",
  "log_type": "stdout",
  "lines": 100,
  "content": "[2025-11-05T11:00:00Z] Starting migration...\n[2025-11-05T11:00:05Z] Processed 1000 records\n[2025-11-05T11:00:10Z] Processed 2000 records"
}
```

```
# Step 5: Stop and cleanup ephemeral program
hoody daemon stop ephemeral-abc123 -c my-container
```

### Workflow 5: Port-Range Programs

**Scenario**: Run multiple instances of an application across a port range.

```
# Step 1: Create a port-range program
hoody daemon create -c my-container
```

```
{
  "name": "Worker Pool",
  "command": "node /app/worker.js --port ${PORT}",
  "user": "app",
  "port_range": {
    "start": 4000,
    "end": 4010
  },
  "environment": {
    "NODE_ENV": "production"
  }
}
```

```
# Step 2: Start a specific port instance
hoody daemon start worker-pool -c my-container --port 4000
```

```
# Step 3: Start multiple instances
hoody daemon start worker-pool -c my-container --port 4001
hoody daemon start worker-pool -c my-container --port 4002
```

```
# Step 4: Check status of all instances
hoody daemon status worker-pool -c my-container
```

```
{
  "id": "worker-pool",
  "name": "Worker Pool",
  "instances": [
    {
      "port": 4000,
      "status": "running",
      "pid": 3001,
      "uptime": 600
    },
    {
      "port": 4001,
      "status": "running",
      "pid": 3002,
      "uptime": 300
    },
    {
      "port": 4002,
      "status": "running",
      "pid": 3003,
      "uptime": 60
    },
    {
      "port": 4003,
      "status": "stopped",
      "pid": null,
      "uptime": null
    }
  ]
}
```

```
# Step 5: Stop a specific instance
hoody daemon stop worker-pool -c my-container --port 4001
```

```
# Step 6: Stop all instances
hoody daemon stop worker-pool -c my-container --all
```

---

## Advanced Operations

### Advanced Workflow 1: Program Enable/Disable Management

**Scenario**: Temporarily disable a program without removing its configuration.

```
# Step 1: Disable a program (stops if running, removes from supervisor)
hoody daemon disable worker -c my-container
```

```
# Step 2: Verify disabled state
hoody daemon get worker -c my-container
```

```
{
  "id": "worker",
  "name": "Background Worker",
  "command": "python /app/worker.py",
  "user": "app",
  "enabled": false,
  "hoody_kit": false,
  "lazy_load": true,
  "boot": false,
  "port_range": null,
  "environment": {},
  "created_at": "2025-11-01T00:00:00Z",
  "updated_at": "2025-11-05T12:00:00Z"
}
```

```
# Step 3: Re-enable when ready
hoody daemon enable worker -c my-container
```

```
# Step 4: Start the re-enabled program
hoody daemon start worker -c my-container
```

### Advanced Workflow 2: Filter and Query Programs

**Scenario**: Find specific programs based on criteria.

```
# List only Hoody Kit services
hoody daemon list -c my-container --filter hoody_kit=true
```

```
# List only enabled programs
hoody daemon list -c my-container --filter enabled=true
```

```
# List programs that start on boot
hoody daemon list -c my-container --filter boot=true
```

```
# List lazy-loaded programs
hoody daemon list -c my-container --filter lazy_load=true
```

```
# Combine filters
hoody daemon list -c my-container --filter enabled=true,boot=true
```

### Advanced Workflow 3: Reset to Default Configuration

**Scenario**: Restore original program configuration after experiments.

```
# Step 1: View current programs before reset
hoody daemon list -c my-container -o json > /tmp/programs-backup.json
```

```
# Step 2: Reset to default snapshot
hoody daemon reset -c my-container
```

This action:
1. Stops all running programs
2. Removes supervisord configurations
3. Restores `programs.default.json` as `programs.json`

```
# Step 3: Verify reset completed
hoody daemon list -c my-container
```

```
[
  {
    "id": "apache2",
    "name": "Apache HTTP Server",
    "command": "apache2ctl -D FOREGROUND",
    "user": "root",
    "enabled": true,
    "hoody_kit": true,
    "lazy_load": false,
    "boot": true,
    "port_range": null,
    "environment": {},
    "created_at": "2025-01-01T00:00:00Z",
    "updated_at": "2025-01-01T00:00:00Z"
  }
]
```

### Advanced Workflow 4: Program Removal

**Scenario**: Permanently remove a program that's no longer needed.

```
# Step 1: Stop the program if running
hoody daemon stop api-server -c my-container
```

```
# Step 2: Remove the program (requires confirmation)
hoody daemon delete api-server -c my-container --yes
```

```
# Step 3: Verify removal
hoody daemon get api-server -c my-container
```

Expected error response:

```
{
  "error": "not_found",
  "message": "Program 'api-server' not found",
  "code": 404
}
```

### Advanced Workflow 5: Error Recovery

**Scenario**: Handle a program that keeps crashing.

```
# Step 1: Check current status
hoody daemon status crashy-app -c my-container
```

```
{
  "id": "crashy-app",
  "name": "Crashy Application",
  "status": "backoff",
  "pid": null,
  "uptime": null,
  "exit_code": 1,
  "restart_count": 5,
  "last_start": "2025-11-05T12:00:00Z",
  "last_stop": "2025-11-05T12:00:05Z",
  "port": null
}
```

```
# Step 2: Check logs for error details
hoody daemon logs crashy-app -c my-container
```

```
{
  "program_id": "crashy-app",
  "log_type": "stderr",
  "lines": 50,
  "content": "[2025-11-05T12:00:00Z] ERROR: Cannot connect to database\n[2025-11-05T12:00:01Z] ERROR: Connection refused at localhost:5432\n[2025-11-05T12:00:01Z] FATAL: Application startup failed"
}
```

```
# Step 3: Fix the issue (update environment, fix code, etc.)
hoody daemon edit crashy-app -c my-container
```

```
{
  "environment": {
    "DATABASE_URL": "postgres://db-host:5432/mydb"
  }
}
```

```
# Step 4: Restart with fixed configuration
hoody daemon start crashy-app -c my-container
```

```
# Step 5: Monitor until stable
hoody daemon status crashy-app -c my-container
```

```
{
  "id": "crashy-app",
  "name": "Crashy Application",
  "status": "running",
  "pid": 7890,
  "uptime": 60,
  "exit_code": null,
  "restart_count": 0,
  "last_start": "2025-11-05T12:10:00Z",
  "last_stop": null,
  "port": null
}
```

### Performance Considerations

1. **Log retrieval**: Use `--lines` parameter to limit log output for large log files
2. **Status polling**: Avoid rapid polling; check status every 5-10 seconds during startup
3. **Port-range limits**: Maximum 1000 ports per range; plan accordingly
4. **Concurrent starts**: Start programs sequentially to avoid resource contention
5. **Boot programs**: Minimize `boot: true` programs to reduce container startup time

---

## Quick Reference

### Essential Commands

| Command | Description |
|---------|-------------|
| `hoody daemon health` | Check daemon service health |
| `hoody daemon list` | List all programs |
| `hoody daemon get <id>` | Get program details |
| `hoody daemon create` | Add new custom program |
| `hoody daemon edit <id>` | Update program config |
| `hoody daemon delete <id>` | Remove program permanently |
| `hoody daemon start <id>` | Start a program |
| `hoody daemon stop <id>` | Stop a program |
| `hoody daemon enable <id>` | Enable disabled program |
| `hoody daemon disable <id>` | Disable program |
| `hoody daemon status <id>` | Get program status |
| `hoody daemon statuses` | Get all program statuses |
| `hoody daemon logs <id>` | View program logs |
| `hoody daemon reset` | Reset to default config |

### Ephemeral Program Commands

| Command | Description |
|---------|-------------|
| `hoody daemon start` | Launch ephemeral program |
| `hoody daemon list` | List ephemeral programs |
| `hoody daemon status <id>` | Get ephemeral status |
| `hoody daemon logs <id>` | View ephemeral logs |
| `hoody daemon stop <id>` | Stop and cleanup ephemeral |

Note: Ephemeral programs are listed separately from persistent programs. Use `hoody daemon list` in the ephemeral context to see only ephemeral programs.

### Common Parameters

| Parameter | Description | Example |
|-----------|-------------|---------|
| `-c <id>` | Target container | `-c my-container` |
| `-o json` | JSON output format | `-o json` |
| `--port <n>` | Specific port instance | `--port 4000` |
| `--all` | All port instances. Applies to stop command for port-range programs. | `--all` |
| `--lines <n>` | Log lines to retrieve | `--lines 100` |
| `--yes` | Skip confirmation | `--yes` |
| `--filter <key>=<val>` | Filter programs. Valid keys: `hoody_kit`, `enabled`, `boot`, `lazy_load` | `--filter enabled=true` |

### Program Configuration Fields

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | Yes | Program display name |
| `command` | string | Yes | Command to execute |
| `user` | string | Yes | System user to run as |
| `port_range` | object | No | Port range configuration |
| `port_range.start` | integer | Yes* | Starting port number |
| `port_range.end` | integer | Yes* | Ending port number |
| `environment` | object | No | Environment variables |
| `enabled` | boolean | No | Enable on creation (default: true) |
| `boot` | boolean | No | Start on container boot |
| `lazy_load` | boolean | No | Load on first request |
| `auto_restart` | boolean | No | Auto-restart on failure |
| `start_retries` | integer | No | Max restart attempts |
| `stop_wait_secs` | integer | No | Graceful stop timeout |

*Required when `port_range` is specified

### Example: Minimal Configuration

```
{
  "name": "My Program",
  "command": "node /app/server.js",
  "user": "app"
}
```

Note: Optional fields like `auto_restart`, `start_retries`, and `stop_wait_secs` can be omitted.

### Status Values

| Status | Description |
|--------|-------------|
| `running` | Program is active and healthy |
| `stopped` | Program is not running |
| `starting` | Program is initializing |
| `stopping` | Program is shutting down |
| `backoff` | Restarting after failure |
| `fatal` | Unrecoverable error |
| `unknown` | Status cannot be determined |

### Response Formats

**Health Check Response:**

```
{
  "status": "healthy",
  "service": "hoody-daemon",
  "version": "1.0.0",
  "timestamp": "2025-11-05T10:30:00Z",
  "uptime": 86400,
  "dependencies": {},
  "metrics": {},
  "checks": {}
}
```

**Program Object:**

```
{
  "id": "program-id",
  "name": "Program Name",
  "command": "executable --args",
  "user": "username",
  "enabled": true,
  "hoody_kit": false,
  "lazy_load": false,
  "boot": true,
  "port_range": null,
  "environment": {},
  "created_at": "2025-11-05T10:30:00Z",
  "updated_at": "2025-11-05T10:30:00Z"
}
```

**Status Object:**

```
{
  "id": "program-id",
  "name": "Program Name",
  "status": "running",
  "pid": 1234,
  "uptime": 3600,
  "exit_code": null,
  "restart_count": 0,
  "last_start": "2025-11-05T10:30:00Z",
  "last_stop": null,
  "port": null
}
```

Note: For port-range programs, the status response includes an `instances` array instead of a single `port` field. See Workflow 5 for an example.

**Logs Response:**

```
{
  "program_id": "program-id",
  "log_type": "stdout",
  "lines": 100,
  "content": "log output here"
}
```

| Field | Type | Description |
|-------|------|-------------|
| `program_id` | string | ID of the program |
| `log_type` | string | Type of log (stdout or stderr) |
| `lines` | integer | Number of log lines |
| `content` | string | Log content |

### Error Responses

**Not Found:**

```
{
  "error": "not_found",
  "message": "Program 'id' not found",
  "code": 404
}
```

**Validation Error:**

```
{
  "error": "validation_error",
  "message": "Invalid program configuration",
  "code": 400,
  "details": {
    "field": "name",
    "issue": "Program name already exists"
  }
}
```

**Conflict Error:**

```
{
  "error": "conflict",
  "message": "Program is already running",
  "code": 409
}
```