Daemon Management
Section titled “Daemon Management”The Daemon Management API lets you manage custom programs running under the container’s supervisord instance. Two program types are supported:
- Persistent programs — stored in
programs.jsonand registered with supervisord. They survive container reboots and are intended for long-running services. - Ephemeral programs (Quick Start) — tracked in
ephemeral.jsononly. They auto-clean when stopped, on container reboot, or when a TTL expires. Use them for one-off jobs, temporary test servers, and CI tasks.
All endpoints are scoped to the daemon container.
Programs
Section titled “Programs”Persistent programs are stored in programs.json and registered with supervisord. Use programs/add for new custom programs, programs/edit/{id} to update an existing one, programs/remove/{id} to delete, and programs/reset to restore the default snapshot.
List all programs
Section titled “List all programs”GET /api/v1/daemon/programs
Retrieves a complete list of all configured daemon programs with their full configuration details. Supports multiple filters that can be combined: hoody_kit, lazy_load, enabled, boot. Optionally include runtime status for each program.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
hoody_kit | query | string | No | Filter by hoody_kit status. Use "true" for Hoody Kit programs only, "false" for user (non-kit) programs only. |
lazy_load | query | string | No | Filter by lazy_load status. Use "true" for lazy-loaded programs only (started on-demand), "false" for programs that auto-start. |
enabled | query | string | No | Filter by enabled status. Use "true" for enabled programs only, "false" for disabled programs only. |
boot | query | string | No | Filter by boot status. Use "true" for programs that auto-start on system boot, "false" for manual-start programs. |
port | query | integer | No | Filter programs by single port number. Returns only programs whose port_range includes this specific port. Example: ?port=8042 returns programs with ranges containing 8042. |
port_from | query | integer | No | Filter by port range start (must be used with port_to). Returns programs whose port ranges overlap with the specified range. A program overlaps when its start is at most port_to and its end is at least port_from. |
port_to | query | integer | No | Filter by port range end (must be used with port_from). Returns programs whose port ranges overlap with the specified range. Multiple programs may be returned if their ranges overlap. |
include_status | query | string | No | Include runtime status for each program. When true, adds a status field to each program showing current running state, instances, and process details. |
include_stats | query | string | No | Include resource stats (CPU, memory, process tree) for each running program. Implies include_status=true. Adds a stats field with pid, started_at, cpu_percent, memory_rss_bytes, process_count, and per-process breakdown. Only present for running programs. |
curl -X GET "https://myproj-abc12345-daemon-1.us-east-1.containers.hoody.icu/api/v1/daemon/programs?enabled=true&include_status=true" \ -H "Authorization: Bearer <your-token>"const programs = await client.daemon.programs.listIterator({ enabled: "true", include_status: "true"});Multiple programs configured:
{ "programs": [ { "id": 1, "name": "web-server", "description": "Nginx web server", "enabled": true, "command": "nginx -g \"daemon off;\"", "boot": true, "delay_seconds": 5, "autorestart": "unexpected", "user": "www-data", "environment": { "NGINX_PORT": "80" }, "directory": "/var/www", "priority": 999, "stdout_logfile": "/var/log/nginx/access.log", "stderr_logfile": "/var/log/nginx/error.log", "hoody_kit": false }, { "id": 2, "name": "my-api-server", "description": "Custom Node.js API server", "enabled": true, "command": "node server.js", "boot": true, "delay_seconds": 5, "autorestart": "unexpected", "user": "nodejs", "environment": { "NODE_ENV": "production", "PORT": "3000" }, "directory": "/opt/my-api", "priority": 999, "stdout_logfile": "/var/log/my-api/access.log", "stderr_logfile": "/var/log/my-api/error.log", "hoody_kit": false } ]}No programs configured:
{ "programs": []}Get a specific program
Section titled “Get a specific program”GET /api/v1/daemon/programs/{id}
Retrieves detailed configuration for a single program by its unique ID. Returns complete program configuration including all optional fields.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | integer | Yes | Unique numeric identifier of the program |
curl -X GET "https://myproj-abc12345-daemon-1.us-east-1.containers.hoody.icu/api/v1/daemon/programs/1" \ -H "Authorization: Bearer <your-token>"const program = await client.daemon.programs.get(1);{ "success": true, "program": { "id": 1, "name": "web-server", "description": "Nginx web server", "enabled": true, "command": "nginx -g \"daemon off;\"", "boot": true, "delay_seconds": 5, "autorestart": "unexpected", "user": "www-data", "environment": {}, "directory": "/var/www", "priority": 999 }}{ "success": false, "error": "Program with ID 999 not found"}Add a new CUSTOM program
Section titled “Add a new CUSTOM program”POST /api/v1/daemon/programs/add
Creates a new daemon program from a JSON request body. The program is validated, added to the configuration, and registered with supervisord if enabled.
For custom programs only (your own code/scripts) — not system services.
- Correct examples:
node app.js,python my_script.py,ruby custom_server.rb,./my-binary - Wrong examples:
apache2,nginx,postgresql,mysql— usesystemctlfor these.
This endpoint takes no parameters.
Request Body
Section titled “Request Body”| Name | Type | Required | Default | Description |
|---|---|---|---|---|
id | integer | No | — | Specific ID to assign (auto-assigned if not provided) |
name | string | Yes | — | Program name (must be unique, cannot contain quotes) |
description | string | No | — | Human-readable description (max 500 chars) |
command | string | Yes | — | Full command to execute including all arguments. Use for custom programs only — node app.js, python main.py, ruby server.rb. Do not use for system services like apache2, nginx, postgresql; use systemctl for those. |
user | string | Yes | — | System user to run as (must exist on the system) |
enabled | boolean | No | true | Enable the program immediately |
boot | boolean | No | false | Start automatically on system boot |
delay_seconds | integer | No | 0 | Seconds to wait before starting on boot (max 3600) |
autorestart | string | No | "unexpected" | Restart policy: "true", "false", or "unexpected" |
directory | string | No | — | Working directory path |
priority | integer | No | 999 | Start priority (1-999, lower starts first) |
stdout_logfile | string | No | — | Path for standard output log |
stderr_logfile | string | No | — | Path for standard error log |
logs_enabled | boolean | No | true | Whether logging is enabled |
log_max_bytes | integer | No | 5242880 | Maximum size of each log file in bytes before rotation |
log_backups | integer | No | 2 | Number of rotated backup log files to keep (max 100) |
environment | object | No | — | Environment variables as key-value strings |
hoody_kit | boolean | No | false | Read-only. Server-derived from the program directory (true iff under /hoody/plugins). Any value supplied in a create/update request body is ignored. |
port_range | object | No | — | Port range for multi-instance programs. Each port creates a separate instance. Contains start and end (1-65535). |
port_param | string | No | "--port" | Parameter name for passing port (e.g., "--port", "-p") |
lazy_load | boolean | No | false | Enable lazy loading (autostart=false). Cannot be combined with boot:true. |
display | string | No | — | X11 DISPLAY number for GUI programs (e.g., ":1") |
terminal_id | integer | No | — | Hoody Terminal session ID (1-65535). Enables web-based terminal access via hoody-terminal. |
terminal_shell | string | No | — | Hoody Terminal shell wrapper. One of bash, zsh, fish, sh, tmux. Requires terminal_id. |
terminal_interactive | boolean | No | — | Override auto-detection of interactive vs service mode for hoody-terminal. |
webhooks | object | No | — | Webhook notification configuration for program lifecycle events |
curl -X POST "https://myproj-abc12345-daemon-1.us-east-1.containers.hoody.icu/api/v1/daemon/programs/add" \ -H "Authorization: Bearer <your-token>" \ -H "Content-Type: application/json" \ -d '{ "name": "nodejs-app", "description": "Production Node.js application", "command": "node server.js", "user": "nodejs", "enabled": true, "boot": true, "delay_seconds": 10, "autorestart": "unexpected", "directory": "/opt/myapp", "priority": 100, "environment": { "NODE_ENV": "production", "PORT": "3000", "DATABASE_URL": "postgresql://localhost/mydb" }, "stdout_logfile": "/var/log/myapp/stdout.log", "stderr_logfile": "/var/log/myapp/stderr.log" }'const result = await client.daemon.programs.add({ name: "nodejs-app", description: "Production Node.js application", command: "node server.js", user: "nodejs", enabled: true, boot: true, delay_seconds: 10, autorestart: "unexpected", directory: "/opt/myapp", priority: 100, environment: { NODE_ENV: "production", PORT: "3000", DATABASE_URL: "postgresql://localhost/mydb" }, stdout_logfile: "/var/log/myapp/stdout.log", stderr_logfile: "/var/log/myapp/stderr.log"});{ "success": true, "id": 2, "program": { "id": 2, "name": "nodejs-app", "description": "Node.js application", "enabled": true, "command": "node app.js", "boot": false, "delay_seconds": 0, "autorestart": "unexpected", "user": "nodejs", "environment": { "NODE_ENV": "production" }, "directory": "/opt/app", "priority": 999 }}Validation error:
{ "success": false, "error": "Field 'name' is required"}System user does not exist:
{ "success": false, "error": "User \"invalid-user\" does not exist on the system"}Edit a program
Section titled “Edit a program”POST /api/v1/daemon/programs/edit/{id}
Updates an existing program configuration using JSON request body. Only provided fields will be updated — unspecified fields retain their current values.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | integer | Yes | Unique numeric identifier of the program |
Request Body
Section titled “Request Body”| Name | Type | Required | Default | Description |
|---|---|---|---|---|
id | integer | No | — | Specific ID to assign (auto-assigned if not provided) |
name | string | Yes | — | Program name (must be unique, cannot contain quotes) |
description | string | No | — | Human-readable description (max 500 chars) |
command | string | Yes | — | Full command to execute including all arguments. Use for custom programs only — node app.js, python main.py, ruby server.rb. Do not use for system services like apache2, nginx, postgresql; use systemctl for those. |
user | string | Yes | — | System user to run as (must exist on the system) |
enabled | boolean | No | true | Enable the program immediately |
boot | boolean | No | false | Start automatically on system boot |
delay_seconds | integer | No | 0 | Seconds to wait before starting on boot (max 3600) |
autorestart | string | No | "unexpected" | Restart policy: "true", "false", or "unexpected" |
directory | string | No | — | Working directory path |
priority | integer | No | 999 | Start priority (1-999, lower starts first) |
stdout_logfile | string | No | — | Path for standard output log |
stderr_logfile | string | No | — | Path for standard error log |
logs_enabled | boolean | No | true | Whether logging is enabled |
log_max_bytes | integer | No | 5242880 | Maximum size of each log file in bytes before rotation |
log_backups | integer | No | 2 | Number of rotated backup log files to keep (max 100) |
environment | object | No | — | Environment variables as key-value strings |
hoody_kit | boolean | No | false | Read-only. Server-derived from the program directory (true iff under /hoody/plugins). Any value supplied in a create/update request body is ignored. |
port_range | object | No | — | Port range for multi-instance programs. Each port creates a separate instance. Contains start and end (1-65535). |
port_param | string | No | "--port" | Parameter name for passing port (e.g., "--port", "-p") |
lazy_load | boolean | No | false | Enable lazy loading (autostart=false). Cannot be combined with boot:true. |
display | string | No | — | X11 DISPLAY number for GUI programs (e.g., ":1") |
terminal_id | integer | No | — | Hoody Terminal session ID (1-65535). Enables web-based terminal access via hoody-terminal. |
terminal_shell | string | No | — | Hoody Terminal shell wrapper. One of bash, zsh, fish, sh, tmux. Requires terminal_id. |
terminal_interactive | boolean | No | — | Override auto-detection of interactive vs service mode for hoody-terminal. |
webhooks | object | No | — | Webhook notification configuration for program lifecycle events |
curl -X POST "https://myproj-abc12345-daemon-1.us-east-1.containers.hoody.icu/api/v1/daemon/programs/edit/1" \ -H "Authorization: Bearer <your-token>" \ -H "Content-Type: application/json" \ -d '{ "name": "nodejs-app", "description": "Completely updated application", "command": "node app.js", "user": "nodejs", "enabled": true, "boot": true, "delay_seconds": 15, "autorestart": "unexpected", "directory": "/opt/newpath", "priority": 50, "environment": { "NODE_ENV": "production" } }'const result = await client.daemon.programs.edit(1, { name: "nodejs-app", description: "Completely updated application", command: "node app.js", user: "nodejs", enabled: true, boot: true, delay_seconds: 15, autorestart: "unexpected", directory: "/opt/newpath", priority: 50, environment: { NODE_ENV: "production" }});{ "success": true, "program": { "id": 1, "name": "updated-app", "description": "Completely updated application", "enabled": true, "command": "node app.js", "boot": true, "delay_seconds": 15, "autorestart": "true", "user": "nodejs", "environment": { "NODE_ENV": "production" }, "directory": "/opt/newpath", "priority": 50 }}{ "success": false, "error": "Field 'name' is required"}{ "success": false, "error": "Program with ID 999 not found"}Remove a program
Section titled “Remove a program”POST /api/v1/daemon/programs/remove/{id}
Permanently deletes a program from the configuration. If the program is running, it will be stopped before removal. This is a destructive operation that cannot be undone.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | integer | Yes | Unique numeric identifier of the program |
curl -X POST "https://myproj-abc12345-daemon-1.us-east-1.containers.hoody.icu/api/v1/daemon/programs/remove/1" \ -H "Authorization: Bearer <your-token>"await client.daemon.programs.remove(1);{ "success": true, "id": 1}{ "success": false, "error": "Program with ID 999 not found"}Reset programs to default
Section titled “Reset programs to default”POST /api/v1/daemon/programs/reset
Replaces the current programs.json with the initial default snapshot (programs.default.json) created at container setup time. Stops all managed programs, removes their supervisord configs, and re-applies the default boot programs. Use this when programs have been misconfigured and a clean slate is needed.
This endpoint takes no parameters.
curl -X POST "https://myproj-abc12345-daemon-1.us-east-1.containers.hoody.icu/api/v1/daemon/programs/reset" \ -H "Authorization: Bearer <your-token>"await client.daemon.programs.reset();{ "success": true}{ "success": false, "error": "Default programs file (programs.default.json) not found or corrupt"}Ephemeral Programs (Quick Start)
Section titled “Ephemeral Programs (Quick Start)”Ephemeral programs are temporary programs created via Quick Start. They are NOT saved to programs.json — they are tracked in ephemeral.json for crash recovery only. They auto-clean on manual stop, program exit, container reboot, or TTL expiry.
Use Quick Start for one-off migrations, temporary test servers, debug tasks, CI ephemeral environments, and custom batch jobs. For permanent programs that must survive reboots, use POST /programs/add instead.
List all ephemeral programs
Section titled “List all ephemeral programs”GET /api/v1/daemon/quick-start
Returns all currently tracked ephemeral programs with their current runtime status. Shows programs that are running or pending cleanup.
This endpoint takes no parameters.
curl -X GET "https://myproj-abc12345-daemon-1.us-east-1.containers.hoody.icu/api/v1/daemon/quick-start" \ -H "Authorization: Bearer <your-token>"const ephemeral = await client.daemon.quickStart.listIterator();Multiple ephemeral programs:
{ "success": true, "count": 2, "ephemeral_programs": [ { "temporary_id": "quick_1731605123", "name": "quick_python_1731605123", "command": "python batch-job.py", "user": "worker", "status": "running", "created_at": "2024-11-14T18:32:03Z", "uptime": "0:05:32" }, { "temporary_id": "quick_1731605456", "name": "my-temp-server", "command": "node server.js", "user": "nodejs", "status": "running", "created_at": "2024-11-14T18:37:36Z", "expires_at": "2024-11-14T19:37:36Z", "uptime": "0:00:08" } ]}No ephemeral programs:
{ "success": true, "count": 0, "ephemeral_programs": []}Launch ephemeral CUSTOM program
Section titled “Launch ephemeral CUSTOM program”POST /api/v1/daemon/quick-start
Creates and starts a temporary custom program that auto-cleans when stopped or on container reboot. Custom programs only — system services (apache2, nginx, etc.) belong under systemctl.
Key features:
- Not saved to
programs.json(temporary only) - Tracked in
ephemeral.jsonfor crash recovery - Always created with
autostart=false(does not auto-start on reboot) - Auto-cleanup on: manual stop, program exit, container reboot, TTL expiry
- Full supervisord configuration support (
autorestart,environment, logs, etc.)
Suited to: one-off data migrations, temporary test servers, debug/dev tasks, CI/CD ephemeral environments, custom batch jobs.
- Use for:
python my_migration.py,node test-server.js,./my-batch-job.sh - Don’t use for: system services like
apache2,nginx,postgresql— usesystemctl.
Use POST /programs/add for permanent custom programs that must survive reboots.
This endpoint takes no parameters.
Request Body
Section titled “Request Body”| Name | Type | Required | Default | Description |
|---|---|---|---|---|
command | string | Yes | — | Command to execute with full arguments |
user | string | Yes | — | System user to run as (must exist on the system) |
name | string | No | — | Custom name (auto-generated if not provided). Cannot contain quotes |
autorestart | string | No | "unexpected" | Restart policy while running: "true", "false", or "unexpected" |
directory | string | No | — | Working directory (defaults to user home if not specified) |
environment | object | No | — | Environment variables as key-value strings |
priority | integer | No | 999 | Start priority (1-999, lower starts first) |
delay_seconds | integer | No | 0 | Delay before starting (seconds, max 3600) |
stdout_logfile | string | No | — | Path for standard output log |
stderr_logfile | string | No | — | Path for standard error log |
logs_enabled | boolean | No | true | Whether logging is enabled |
log_max_bytes | integer | No | 5242880 | Maximum size of each log file in bytes before rotation |
log_backups | integer | No | 2 | Number of rotated backup log files to keep (max 100) |
ttl | integer | No | — | Time-to-live in seconds. Program auto-stops after this duration (1-86400) |
wait | boolean | No | false | Wait for program to reach RUNNING state before returning |
timeout | integer | No | 30 | Timeout in seconds when wait=true (1-300) |
display | string | No | — | X11 DISPLAY number for GUI programs |
terminal_id | integer | No | — | Hoody Terminal session ID (1-65535) |
terminal_shell | string | No | — | Hoody Terminal shell wrapper |
terminal_interactive | boolean | No | — | Override auto-detection of interactive vs service mode |
curl -X POST "https://myproj-abc12345-daemon-1.us-east-1.containers.hoody.icu/api/v1/daemon/quick-start" \ -H "Authorization: Bearer <your-token>" \ -H "Content-Type: application/json" \ -d '{ "command": "python batch-job.py", "user": "worker", "name": "data-migration", "autorestart": "unexpected", "directory": "/opt/scripts", "environment": { "DB_HOST": "localhost", "MODE": "production" }, "ttl": 3600, "wait": true }'const ephemeral = await client.daemon.quickStart.launch({ command: "python batch-job.py", user: "worker", name: "data-migration", autorestart: "unexpected", directory: "/opt/scripts", environment: { DB_HOST: "localhost", MODE: "production" }, ttl: 3600, wait: true});Program started (without wait):
{ "success": true, "temporary_id": "quick_1731605123", "name": "quick_python_1731605123", "status": "running", "created_at": "2024-11-14T18:32:03Z"}Program started (with wait=true):
{ "success": true, "temporary_id": "quick_1731605123", "name": "quick_python_1731605123", "status": "running", "pid": 12345, "uptime": "0:00:05", "created_at": "2024-11-14T18:32:03Z"}Program with TTL (auto-stop):
{ "success": true, "temporary_id": "quick_1731605789", "name": "batch-job", "status": "running", "pid": 12399, "uptime": "0:00:45", "created_at": "2024-11-14T18:43:09Z", "expires_at": "2024-11-14T19:43:09Z"}Required field missing:
{ "success": false, "error": "Field 'command' is required"}System user does not exist:
{ "success": false, "error": "User \"invalid-user\" does not exist on the system"}Directory does not exist:
{ "success": false, "error": "Directory '/opt/missing' does not exist"}Name contains quotes:
{ "success": false, "error": "Name cannot contain quotes"}Get ephemeral program status
Section titled “Get ephemeral program status”GET /api/v1/daemon/quick-start/{id}/status
Retrieves current runtime status for a specific ephemeral program by its temporary_id.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Temporary ID of the ephemeral program (format: quick_<timestamp>) |
curl -X GET "https://myproj-abc12345-daemon-1.us-east-1.containers.hoody.icu/api/v1/daemon/quick-start/quick_1731605123/status" \ -H "Authorization: Bearer <your-token>"const status = await client.daemon.quickStart.getStatus("quick_1731605123");Program is running:
{ "success": true, "temporary_id": "quick_1731605123", "name": "quick_python_1731605123", "status": "running", "pid": 12345, "uptime": "0:05:32", "created_at": "2024-11-14T18:32:03Z"}Program is still starting — pid and uptime are absent until it reaches running:
{ "success": true, "temporary_id": "quick_1731605456", "name": "my-temp-server", "status": "starting", "created_at": "2024-11-14T18:37:36Z"}Program with TTL expiry:
{ "success": true, "temporary_id": "quick_1731605789", "name": "batch-job", "status": "running", "pid": 12399, "uptime": "0:00:45", "created_at": "2024-11-14T18:43:09Z", "expires_at": "2024-11-14T19:43:09Z"}{ "success": false, "error": "Ephemeral program with ID quick_1731605000 not found"}Get ephemeral program logs
Section titled “Get ephemeral program logs”GET /api/v1/daemon/quick-start/{id}/logs
Retrieve the last N lines from an ephemeral program’s stdout or stderr log file.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Ephemeral program temporary ID |
type | query | string | No | Log stream: stdout or stderr. Default: "stdout" |
lines | query | integer | No | Number of lines to return from end of file. Default: 100 |
curl -X GET "https://myproj-abc12345-daemon-1.us-east-1.containers.hoody.icu/api/v1/daemon/quick-start/quick_1731605123/logs?type=stdout&lines=50" \ -H "Authorization: Bearer <your-token>"const logs = await client.daemon.quickStart.getEphemeralLogs("quick_1731605123", { type: "stdout", lines: 50});{ "success": true, "logs": "2024-11-14T18:32:03Z INFO Starting batch job\n2024-11-14T18:32:04Z INFO Processing 1000 records\n2024-11-14T18:32:05Z INFO Batch job completed\n", "type": "stdout", "lines": 50, "log_file": "/tmp/quick_python_1731605123.out.log"}{ "success": false, "error": "Invalid log type 'info' (must be 'stdout' or 'stderr')"}{ "success": false, "error": "Ephemeral program with ID quick_1731605000 not found"}Stop ephemeral program
Section titled “Stop ephemeral program”POST /api/v1/daemon/quick-start/{id}/stop
Stops the ephemeral program and removes its configuration completely.
Actions performed:
- Stop program via
supervisorctl - Delete supervisord config file
- Remove from
ephemeral.jsontracking - Update supervisord
Result: Program is completely removed from the system (cannot be restarted).
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Temporary ID of the ephemeral program to stop |
curl -X POST "https://myproj-abc12345-daemon-1.us-east-1.containers.hoody.icu/api/v1/daemon/quick-start/quick_1731605123/stop" \ -H "Authorization: Bearer <your-token>"const result = await client.daemon.quickStart.stop("quick_1731605123");{ "success": true, "temporary_id": "quick_1731605123", "cleaned_up": true, "message": "Program stopped and configuration removed"}{ "success": false, "error": "Ephemeral program with ID quick_1731605000 not found"}