Skip to content

Reconciliation

Reconciliation is the heart of Hostwright, and it is deliberately boring: deterministic, observable, and hard to corrupt.

Reconciliation cycle: observe actual state, diff against desired, plan actions, then the confirmed apply step, looping back to observe; dry-run stops after plan.

  1. Load desired state from the manifest.
  2. Observe runtime state through the RuntimeAdapter.
  3. Compute drift.
  4. Produce a dry-run plan with a deterministic hash.
  5. Apply only through the confirmed single-action persistence gate.
  6. Record events.

The planner maps the supported manifest subset to runtime-shaped desired state, accepts optional adapter-shaped observed state, runs policy checks, and emits typed drift records, typed issues, typed planned actions, and a deterministic plan hash.

  • hostwright plan renders desired-state and policy diagnostics. It does not perform live runtime observation by default, and it says so explicitly in its output.
  • hostwright apply recomputes the plan against a live observation, requires a matching --confirm-plan hash, persists operation intent before mutation, and executes exactly one executable action: createMissingService, a restart-policy-allowed startManagedService, or a restart-policy-allowed restartManagedService.
  • hostwright cleanup is separate from apply, with its own dry-run token gate. See the safety model.
  • hostwrightd --foreground runs the loop continuously — observe, plan, record — but never calls the mutation hook. See Daemon.

The planner detects:

  • missing desired services;
  • unmanaged observed services;
  • stopped, exited, failed, and missing lifecycle states;
  • image drift, port drift, mount drift;
  • unhealthy or unknown health state where policy requires health;
  • duplicate observed identities;
  • unsupported unknown observed lifecycle states;
  • unavailable observation.

Only createMissingService and the restart-policy-allowed start/restart actions can be marked executable. Every other action is rendered as unavailable — visible in the plan, but not runnable.

  • Planning must be deterministic — same inputs, same plan, same hash.
  • Desired state and observed state remain separate inputs.
  • Drift must be explainable: every record carries a typed reason.
  • Plan rendering must not expose raw secrets.
  • Mutation must require plan-hash confirmation.
  • Operation intent must be persisted before mutation.
  • Failures must be observable through events.
  • Managed restart requires Hostwright ownership, live observed running state, a fresh persisted unhealthy health result, and recovery records.