Plans, State, And Audit
HostShift separates planning from execution. plan, prepare, sync, and verify expose the same source-safety metadata so automation can refuse risky work before apply.
Plan Shape
Section titled “Plan Shape”hostshift plan --json returns:
{ "profile": "example", "sourcePolicy": "strict-read-only", "sourceWillBeModified": false, "actions": [], "streams": [], "blockers": [], "warnings": []}Actions
Section titled “Actions”Actions are local, source, or target commands:
Action{id, phase, hostRole, impact, command, preconditions, rollback}Valid phases:
discoverplanpreparesyncverifycutoverrollback
Valid host roles:
sourcetargetlocal
Valid impacts:
read-onlywriteservicenetwork
Any source action must have impact: read-only. Plan validation fails otherwise.
Streams
Section titled “Streams”Streams pipe a source read command into a target write command:
StreamAction{id, phase, sourceCommand, targetCommand, preconditions, rollback}Examples:
tar --createtotar --extractdocker image savetodocker image loadmysqldumptomysqlpg_dumptopg_restore- existing Docker volume snapshot tar
catto targettar --extract
The source command is validated by the source command guard. The target command is validated by the target command guard and may be sudo-wrapped only when HOSTSHIFT_TARGET_SUDO=1.
Blockers
Section titled “Blockers”Common blockers:
- profile is not approved
sourcePolicyis notstrict-read-only- target SSH alias is missing
- target platform is unknown
- target platform is EOL or unsupported
- package capability cannot be mapped to a target package
- a discovered Docker named volume has no reviewed strategy
- a Docker volume
snapshotstrategy has no existingsnapshotPath
Apply should not run while blockers are present.
Warnings
Section titled “Warnings”Warnings call out risk that does not necessarily block apply:
- source platform is EOL but still read-only
- cross-distribution migration requires compatibility checks
Warnings should be handled through explicit checks in the profile.
State Directory
Section titled “State Directory”Apply phases can write state:
hostshift sync --profile profile.yaml --apply --state-dir .hostshift --run-id sync-001 --jsonState path:
<state-dir>/runs/<run-id>/state.jsonA per-run OS file lock prevents two dry-run/apply/resume processes from writing or executing the same run concurrently. status and resume preview can still read the atomically replaced state document.
If --state-dir is omitted, HostShift uses:
HOSTSHIFT_STATE_DIR- the OS user config directory under
hostshift .hostshiftas fallback
If --run-id is omitted, phase commands generate a collision-resistant ID and return it as runId in their output so the saved state can be addressed later.
Audit Log
Section titled “Audit Log”Audit events are appended as JSONL:
<state-dir>/runs/<run-id>/audit.jsonlEach event includes:
timerunIdphaseaction- optional
message
The state document includes:
planHash: SHA-256 fingerprint of the phase profile, hosts, blockers, actions, and streamsstatus:dry-run,blocked,running,failed, orcompletedcompleted: action and stream IDs durably completed by applyfailedActionand redactedlastErrorwhen execution returned an erroruncertainActionwhile a remote operation is running or may have partially completed
Status And Resume
Section titled “Status And Resume”Use status to read state:
hostshift status --state-dir .hostshift --run-id sync-001 --jsonUse resume without --apply to preview completed and pending steps without changing the saved state:
hostshift resume --profile migration.profile.yaml --state-dir .hostshift --run-id sync-001 --jsonUse --apply to continue the same phase. HostShift rebuilds the plan and requires the saved fingerprint to match before it skips completed IDs and executes pending IDs.
hostshift resume --profile migration.profile.yaml --state-dir .hostshift --run-id sync-001 --apply --jsonIf failedAction or uncertainAction is present, inspect the target and pass the exact ID with --retry-failed. HostShift never silently retries a potentially partial remote operation.