# ezx — Features

ezx is a deterministic, scriptable container entrypoint engine: a single Go binary driven by a declarative JavaScript script that replaces fragile bash entrypoint trees with supervision, readiness, scheduling, and secrets handling.

## Feature reference

1. **No shell boilerplate** — One Go binary + a declarative JS script. Readable, testable, and no shell dependencies.
2. **Dependency graph (DAG)** — Flat nodes + dependsOn edges: fan-in, shared dependencies, and diamonds — no nested tree required.
3. **Per-edge wait modes** — dependsOnEdges picks started, ready, or exit per dependency — wait for one dep to be ready while another only needs to start.
4. **Oneshot services** — oneshot: true runs a process to completion; dependents start after it exits 0. Retryable via restart.
5. **Per-service logging with rotation** — Route a node's stdout/stderr to its own rotating file: log.stdout: "file", filePath, maxBytes, maxBackups.
6. **Env-driven determinism** — Environment variables map to config files and CLI flags declaratively. Same env, same output, every time.
7. **Secret filtering** — filterEnv / filterEnvPattern strips sensitive vars before spawning any child.
8. **PID-1 init duties** — Built-in zombie reaping, signal forwarding, and graceful drain — or hand PID 1 to the app if you prefer.
9. **Two launch modes** — Choose exec mode (app is PID 1) or supervised mode (ezx stays PID 1). Your container, your call.
10. **Health & scheduling** — /readyz, /livez, /healthz, and cron-driven scheduler with readiness gates are built in.
11. **Runtime API** — Expose user-defined HTTP routes on the shared health server for manual triggers and runtime ops.
12. **Declarative builders** — Render key=value, table/matrix, INI, and deterministic YAML from structured objects.

## How it works

ezx loads a JavaScript entrypoint script against its Go-hosted JS engine (goja). The script declaratively describes everything: which files to provision, how to build CLI arguments from env, which processes to spawn, how they depend on each other, and how to supervise them.

The core abstraction is the dependency graph — a ProcessNode connected by explicit dependsOn edges (the flat `nodes`/`dependsOn` form). A node starts after all of its dependencies have started; per-edge wait modes let each dependency independently gate on started, ready, or exit; oneshot nodes run to completion and act as success gates; siblings / independent nodes start in parallel; and any node can carry a restart policy, a health server, a scheduler (cron), forwardSignals, a probe, and graceful shutdown config.

## Launch modes

**Mode A — exec:** ezx does the setup (env templating, file provisioning, spawning support processes), then syscall.Exec the app. The app becomes PID 1 and handles its own signals natively. Zero supervision overhead — but no restart/health-check safety net. Must be a leaf node and is mutually exclusive with health.

**Mode B — supervised:** ezx stays PID 1. Each node gets restart, health/readiness HTTP, scheduler, forwardSignals, probe, shutdown, and dependency edges via dependsOn / dependsOnEdges. ezx reaps zombies and forwards signals. Declare one of those (or execDefault: false) — a lone node with none of them is auto-exec'd instead.

