Plan before mutation.
Every run computes a reviewable plan from the manifest.plan is non-mutating; mutation requires exact confirmation and crosses the same identity, provider, and ledger boundaries.
# Signed, authenticated local daemon required$ hostwright validate hostwright.yaml$ hostwright up hostwright.yaml --dry-run# Review images, resources, ownership and actions# Copy the reviewed planSHA256$ hostwright up hostwright.yaml \ --confirm-plan <planSHA256>$ hostwright status hostwright.yaml# Every later change needs a fresh reviewed hashApple container is a runtime. Local stacks still need a control plane.
Apple container gives the Mac a native container runtime: lightweight Linux VMs, an OCI image flow, and a command surface built for Apple silicon.
Running a multi-service stack requires more than starting containers: declared state, validation, health checks, restart policy, drift detection between declared and observed state, and ownership-checked cleanup.
Hostwright is that layer. The accepted v0.0.2 scope is one Mac; multi-Mac orchestration is deferred.
What Hostwright does
Current capabilities of the CLI and daemon.
Declares services in hostwright.yaml
Manifest v3 describes local desired state with explicit CPU and memory requests and limits; legacy v1/v2 input has a deterministic migration preview.
Plans changes before mutation
Plans are deterministic and reviewable; live mutation remains bound to exact confirmation, identity, provider, and state gates.
Routes operations through a RuntimeAdapter
Apple container observation and narrow lifecycle calls cross one typed boundary; no other code path reaches the runtime.
Tracks local state
SQLite schema v24 records desired/observed state, events, operations, ownership UUIDs, provider binding, fencing, and recovery.
Detects drift
Typed deterministic drift and plan actions compare declared and observed state without guessing unsupported runtime shapes.
Runs doctor checks
Runs safe local checks for OS, architecture, Swift, manifest presence, and `container` executable lookup.
Treats destruction as explicit
Cleanup is dry-run first and token-confirmed, limited to exact owned eligible containers. Broad garbage collection is not implemented.
The CLI
hostwright init
hostwright capabilities --json
hostwright migrate preview hostwright.yaml
hostwright validate
hostwright plan
hostwright paths --json
hostwright status hostwright.yaml --output json
hostwright doctorhostwright up hostwright.yaml --dry-run
hostwright up hostwright.yaml --confirm-plan <planSHA256>
hostwright down hostwright.yaml --dry-runDevelopment commands require the signed, authenticated local daemon and selected provider. Review a fresh dry-run hash before confirming each mutation; release qualification is pending.
Architecture
Hostwright owns versioned intent, UUID identity, SQLite ledgers, planning, policy, and recovery state. Apple container owns execution. The Runtime Provider API is the only mutation boundary.
Declare a stack in one file
version: 3
project: api-local
services:
web:
image: docker.io/library/python@sha256:26730869004e2b9c4b9ad09cab8625e81d256d1ce97e72df5520e806b1709f92
resources:
requests:
cpus: 1
memory: 512MiB
limits:
cpus: 1
memory: 512MiB
command: ["python3", "-m", "http.server", "8080", "--bind", "0.0.0.0"]
ports:
- "18080:8080"Safety model
Defaults are conservative and mutation is always explicit.
Plan before mutation
Runtime changes are computed and reviewable before they run.
Dry-run for cleanup
Cleanup previews exact identity and eligibility before a separately confirmed owned-resource deletion.
Explicit destructive confirmation
Removing real resources requires an intentional, confirmed action.
Conservative validation
Unsafe or ambiguous manifests are refused, not guessed at.
No hidden runtime mutation
Mutation exists only behind explicit plan/cleanup confirmation and the typed, recorded provider path.
Ownership-tracked cleanup
Cleanup can touch only resources Hostwright can prove it owns; unmanaged resources are never inferred from names.
No secret leakage in logs
Secrets and credentials are kept out of events and log output.

