Skip to main content
Once past flag parsing, uniac deploy prints exactly one thing on stdout: the frame the finished run leaves behind. It holds two registers — the run record, what the run did, then the state block, what it established — separated by a blank line, the state block at the margin because it is the answer rather than a step. uniac status prints the state block alone — and an error block beneath it when the read fails. Both on stdout; the reporting path writes nothing to stderr. Either command does write there when it never gets past flag parsing — -h, or a malformed invocation — printing the usage block on stderr and nothing at all on stdout (see Exit codes). Live progress belongs to deploy and goes to stderr, and only when stderr is a terminal with real width. The live area erases itself when the run ends, so stdout is a function of the run alone — identical bytes whether or not anyone watched. UNIAC_PROGRESS=1 streams plain progress lines to stderr instead (the CI form), UNIAC_PROGRESS=0 silences it; neither touches stdout, and neither affects uniac status, which narrates nothing.

The run record

The record is the run’s task tree: the root line deploy <target> at the margin, then one line per stage beneath it, indented two spaces, in the order the run takes them — plan summarized by the deployable digest, link by the project slug, build by <N> image(s), then push <service> by the image digest and deploy <service> by the settled status. Both digests are shortened to sha256: plus twelve hex characters; the settled status is the platform’s own word for what the service ended as. The glyphs are done and failed. Ctrl-C fails the stage that was in flight — , with the interruption as the last line of its evidence — and the run exits under that stage’s own code. The root line always carries a duration; a stage carries one only when it took a second or more. Durations render as 480ms, 41.0s, 2m03s. A clean run stays one level deep: the build’s own steps live in the live view, not in the record. The frames under Failures show the record as it renders.

The state block

The state block is the platform’s account of the project — the same view the dashboard shows, and the same rendering both commands print. An omitted line is an absent fact, never a hidden one, and the quiet normal says nothing: an active lifecycle, no task in flight, and replicas as requested add no rows.
Services appear in name order. Columns align within a block, not across the page — read a line by its label, never by a column offset.

Volume entities

After the services come the project’s durable volumes, one block each. An indented volume row is a mount on a service; a volume row at the margin opens an entity, whose own facts are its size and its lifecycle state: Only the whole-project uniac status lists the entities. uniac deploy and uniac status <service> carry the mount row on the service and nothing else, so an unattached volume — data intact, held by nobody — appears nowhere but here. A platform that does not serve the volume read costs this section and nothing else: the status still renders, and still exits on its own verdict.

Failures

uniac status has no task tree, so it says what went wrong in an error block, after whatever state it did establish and a blank line — when the read established nothing, that blank line is the run’s first byte:
uniac deploy says both of those things in the frame instead: the code annotates the root line, and the message closes the evidence inset beneath the task that broke. A deploy frame has no error block — the root-line code and the exit status are what a consumer branches on.
Only the path to the failure expands; finished siblings stay one-liners. Evidence is what the broken task retained — the progress lines it kept, then the error — so the message closes the block rather than being all of it, and a task that narrated several steps insets those too. The run above reached nothing, so it established no state and none is invented for it: the frame is the record alone. A failure that lands before the manifest names a deployment leaves the label bare, too: ✗ deploy manifest (0ms). When the build is what broke, the board it was drawing stands in for that narration — one line per container, pull <ref> or build ./<root> (just build . when the root is the project directory), with a step’s latest status inset beneath it when it has said one — and the build’s own error still closes the block. Linking had already succeeded here, so the run does have state to report:
A retryable failure annotates the root as <code> — retryable: ✗ deploy main push — retryable (136ms). A failed run always leaves its frame and whatever state it did establish, so never read a non-zero exit as “no output” — only the 2 a malformed invocation earns prints none.