Output and logs
NXD writes to two places at once, with different jobs.
| Channel | Contains | Audience |
|---|---|---|
| Terminal | Compact progress milestones and a final summary | You, watching a deployment |
Log file (.log/nxd-<host>.log) | Complete untruncated output: raw subprocess stdout and stderr, Disko traces, store transfer listings, activation debug | You, afterwards, working out what happened |
Every lifecycle operation uses both, whether it targets one host or twenty. The terminal never becomes the only record, and the log file never becomes the thing you have to read to follow a normal run.
Progress lines name what they did
A progress message states the specific resource, the action, and the parameters that matter. Vague provider phases such as “VMware action completed” are deliberately not allowed — a message that does not say which resource it touched is not useful in a postmortem.
Step formatting depends on duration, to avoid noise:
-
Fast steps emit a single completed line with exact parameters:
[medo-test] Configured DNS resolvers (1.1.1.1, 8.8.8.8) -
Slow steps emit an active line when they start and a completion line annotated with how long they took:
[medo-test] Partitioning & formatting disk /dev/vda with Disko... [medo-test] Partitioned & formatted disk /dev/vda (ext4) (18s)
A fast step never emits both a started and a completed line for the same work.
Secrets are redacted in both channels
Secret values, private keys, tokens, and confidential parameters are redacted from the terminal and from log files. A log file is a durable artifact that often gets pasted into an issue or a chat, so it is held to the same standard as anything else that leaves the machine.
Profiling is separate
--profile reports internal phase timings for diagnosing where a slow run spent
its time:
PROFILE phase=inventory-evaluation duration_ms=4120
It covers inventory evaluation, runtime composition, selected-output evaluation, endpoint attestation, secret resolution, observation, planning, apply, and total time.
Profiling output goes to stderr (or structured JSON) so it never disturbs the normal progress stream or any JSON on stdout. Progress reports human durations for milestones you care about; profiling reports machine-readable latency for phases you are investigating. They share the same underlying timers and do not duplicate each other’s lines.
Phase names are stable operator diagnostics. They are not a second lifecycle model, and commands do not invent provider phases by parsing action names.
Build placement is reported
Provider progress reports both the configured and the resolved build
placement, so an auto setting never leaves you guessing where the work
actually happened:
✓ [medo] build placement configured=auto builder=deploy@utils
For the full invariants, see docs/architecture-design/logging-and-progress.md
in the repository.