Skip to content
Hoody.com

Use these endpoints to enable, disable, start, and stop daemon programs managed by supervisord. Enable and disable change a program’s registration state. A disable that answers 200 has removed the program from supervisord’s configuration, so nothing can start it; a disable whose configuration removal failed answers 400 with the program already persisted as disabled and its configuration still loaded, and it has to be disabled again once the cause is fixed. Start requires an enabled program; stop works whatever the enabled flag says.

Enable and disable set whether a program may run. Disabling a running program removes its supervisord definition and stops it as part of the same call; enabling writes the definition only for programs the daemon applies, as described below.

Sets enabled: true and saves it. The supervisord definition is written at once only for a program with boot, lazy_load, a port_range or an effective sandbox, so enabling a boot: true program can start it; an ordinary program is registered when it is first started. A sandboxed program whose definition cannot be applied is a 400 after the flag was saved (enabled but its supervisord config was NOT applied); an ordinary program’s apply failure still returns 200, so a 200 does not prove the definition was installed.

NameInTypeRequiredDescription
idpathintegerYesUnique numeric identifier of the program. An id that is not a valid i32 (a word, an empty segment, a number too large) never reaches the handler: the path extractor refuses it with a plain-text 404, on every route that takes an id, which is NOT the documented JSON 404 of the routes that have one. An id that parses but names no program is the handler’s own answer, a 400 carrying the {success: false, error: ...} envelope, except on the routes that document a 404.
{
"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
}
}
Terminal window
# Enable a program
hoody daemon programs enable "$PROGRAM_ID" -c "$CONTAINER_ID"

Disables the program and removes it from supervisord configuration. The program will be stopped if currently running. The row is persisted first and the supervisord configuration is removed afterwards, so a removal that fails answers 400 saying the program is disabled but its supervisord configuration was not removed. Repair the cause and disable the program again: no later startup removes that configuration, because the startup sweep only collects configurations whose program id is gone. When the daemon kept firewall rules for a definition that may still be running unconfined, the same message says so.

NameInTypeRequiredDescription
idpathintegerYesUnique numeric identifier of the program. An id that is not a valid i32 (a word, an empty segment, a number too large) never reaches the handler: the path extractor refuses it with a plain-text 404, on every route that takes an id, which is NOT the documented JSON 404 of the routes that have one. An id that parses but names no program is the handler’s own answer, a 400 carrying the {success: false, error: ...} envelope, except on the routes that document a 404.
{
"success": true,
"program": {
"id": 1,
"name": "web-server",
"description": "Nginx web server",
"enabled": false,
"command": "nginx -g \"daemon off;\"",
"boot": true,
"delay_seconds": 5,
"autorestart": "unexpected",
"user": "www-data",
"environment": {},
"directory": "/var/www",
"priority": 999
}
}
Terminal window
# Disable a program, which stops it
hoody daemon programs disable "$PROGRAM_ID" -c "$CONTAINER_ID"

Start (on an enabled program) and stop act immediately via supervisorctl. Both need a JSON body with Content-Type: application/json, at least {}: a missing body, a request without the right Content-Type, a body that is not JSON, or a field of the wrong type is a 400 carrying the {success: false, error} envelope, and a body over 1 MiB a 413. Port-range programs are multi-instance, with each port in the configured range as a separate running process, and these endpoints address one instance at a time unless all: true is sent to stop.

Issues the start immediately via supervisorctl. For port-range programs, the port parameter is required to specify which instance to start. The optional wait parameter blocks until the program reaches the RUNNING state, and if_not_running makes the call idempotent. The program must be enabled before it can be started.

Without wait, a 200 reports that the start was issued, not that the program is running: a newly started port-range instance gets instance.status: "starting", and a standard program returns only success (plus already_running in idempotent mode). Send wait: true, or poll GET /status/{id}, to learn the outcome. A confirmed start failure, such as a start supervisord refused, is a 400 whose error says why (program <name> did not start: <reason>). When it was the first attempt that failed, supervisord may still retry the program and it may come up, so check its status.

A standard program answers {"success": true} (plus already_running with if_not_running); only a port-range start carries instance.

For a sandboxed program, a launch the sandbox refuses for its configuration exits 78 with a sandbox: <reason> line on stderr, a launch cancelled by a stop signal or a failed handshake exits 143 unless a wrapper stage already exited with its own nonzero status, and a signal death is 128+n. Status shows only the state, typically fatal, so read the program’s stderr log.

With wait: true, a program that finishes during the wait answers 200 with status: "exited" and its last_run, whatever the exit code; a start that ends in fatal, or that supervisord refused, is a 400 that carries last_run. A finished run never counts as ready: a caller that needs the program to serve (a ready_port, or if_not_running) gets a 400 saying it exited before accepting connections. A start whose reply from supervisord was lost answers 502 and is never retried: read the program’s status before starting it again.

NameInTypeRequiredDescription
idpathintegerYesUnique numeric identifier of the program. An id that is not a valid i32 (a word, an empty segment, a number too large) never reaches the handler: the path extractor refuses it with a plain-text 404, on every route that takes an id, which is NOT the documented JSON 404 of the routes that have one. An id that parses but names no program is the handler’s own answer, a 400 carrying the {success: false, error: ...} envelope, except on the routes that document a 404.
FieldTypeRequiredDefaultDescription
portintegerNo (required for port-range programs)—Port number to start (required for port-range programs)
waitbooleanNofalsePoll until the program is running and, when it declares ready_port, until 127.0.0.1:<ready_port> accepts a TCP connection. A listener bound only to another address never satisfies it.
timeoutintegerNo30Readiness polling budget in seconds (0 to 4294967295). Configuration and the supervisord start happen before it begins, so the request can take longer; it is not an HTTP deadline.
if_not_runningbooleanNofalseIdempotent mode: reports already_running. Concurrent idempotent starts for the same id and port share one start whatever their own wait and timeout, so a waiting caller can receive an earlier non-waiting caller’s starting. After it finished, only a waited result that found the program ready is reused, for about 2 seconds, and only while that run is observably alive and has not reported an end; anything else (a start nobody waited for, a failed or finished result, a run the daemon cannot observe) is not reused, and the next caller checks again and starts the program if it is not running. A caller whose wait for a shared start runs out gets a 400 (start is still in progress ... retry) and no second start. The already-running shortcut for a port-range instance does not check ready_port.
{
"port": 8042
}
{
"success": true
}
Terminal window
# Start one instance. The CLI's own HTTP timeout is 30 seconds, so do not rely on
# --wait for longer readiness budgets: start, then poll the instance's status.
hoody daemon programs start "$PROGRAM_ID" --port 8042 -c "$CONTAINER_ID"
hoody -o json daemon programs status "$PROGRAM_ID" --port 8042 -c "$CONTAINER_ID"

Issues the stop immediately via supervisorctl. For port-range programs, specify port to stop a specific instance or all: true to stop every instance; when both are sent, port wins. A standard program ignores both fields, and a stop does not require the program to be enabled. The handler discards the result of the underlying supervisorctl stop, so a 200 reports that the stop was issued rather than that the process is gone; read GET /status/{id} to confirm.

NameInTypeRequiredDescription
idpathintegerYesUnique numeric identifier of the program. An id that is not a valid i32 (a word, an empty segment, a number too large) never reaches the handler: the path extractor refuses it with a plain-text 404, on every route that takes an id, which is NOT the documented JSON 404 of the routes that have one. An id that parses but names no program is the handler’s own answer, a 400 carrying the {success: false, error: ...} envelope, except on the routes that document a 404.
FieldTypeRequiredDefaultDescription
portintegerNo—Specific port to stop
allbooleanNo—Stop all instances (for port-range programs)
{
"port": 8042
}
{
"success": true
}
Terminal window
# Stop every instance of a port-range program
hoody daemon programs stop "$PROGRAM_ID" --all -c "$CONTAINER_ID"