Skip to content

Review an app suite

Steps 1 and 2 are read-only: validate and plan touch nothing. Step 3 shows the confirmed lifecycle command that would converge the suite, labeled as the mutating step it is.

examples/app-suite/hostwright.yaml declares a web service and a worker:

version: 2
project: app-suite
services:
web:
image: ghcr.io/example/web:latest
command: ["serve"]
ports:
- "8080:8080"
env:
APP_ENV: development
API_BASE_URL: http://localhost:8081
health:
command: ["curl", "-f", "http://localhost:8080/health"]
interval: 15s
restart:
policy: on-failure
worker:
image: ghcr.io/example/worker:latest
env:
QUEUE_NAME: default
restart:
policy: no
Terminal window
hostwright validate examples/app-suite/hostwright.yaml
hostwright plan examples/app-suite/hostwright.yaml --output json

The plan covers both services: typed issues from the policy checks (duplicate host ports, broad bind addresses, unsafe mounts, secret-like env values), drift records per service if observed state is available, and one deterministic hash for the whole plan.

2. What health and restart declarations do

Section titled “2. What health and restart declarations do”
  • health.command (this example’s legacy scalar form) is executed by the daemon as an in-process loopback probe for allowlisted command shapes. Results are persisted and feed drift detection (“unhealthy where policy requires health”). migrate preview converts it into an equivalent typed liveness probe automatically; typed probes also support a real container-exec action for startup, readiness, and liveness checks. See Health, restart, and updates.
  • restart.policy gates the managed start and managed restart actions. policy: no (as on worker) is a manual hold: Hostwright will never mark a start or restart of that service executable. Restart state also tracks max attempts, backoff, and crash-loop blocking.

If both services are missing, hostwright plan reports two create actions under one plan hash. hostwright up confirms and executes that same plan as one operation: it creates both services, in the order their dependsOn declarations require (this example declares none, so both are eligible immediately), with bounded parallelism, and re-observes between waves so a later step never acts on stale information.

Terminal window
hostwright up examples/app-suite/hostwright.yaml --dry-run # one plan, both services
hostwright up examples/app-suite/hostwright.yaml \
--state-db /tmp/hostwright.sqlite --confirm-plan <hash> # converges both
hostwright status examples/app-suite/hostwright.yaml --state-db /tmp/hostwright.sqlite

A confirmed plan is bound to the observation it was computed against. If reality changes between the dry run and confirmation, for example another process starts one of the services, the confirmed hash no longer matches and the command refuses with a confirmation-mismatch error (exit code 70) rather than acting on stale intent.