axis command
The axis application loads a project, invokes construction, presents progress, launches a destination command and exposes the saved log. It supplies distribution defaults and storage locations. It is an application adapter, not a reusable domain concept.
Source: main.go. Project wiring: project.go.
Command vocabulary
A project is the selected directory containing axis.lua. A product is the named output request. A destination is the explicitly named machine configuration. A phase is one observed piece of work with an identity and terminal outcome. These are the meanings needed to use this command interface.
axis -C examples/system plan system --target axis:aarch64-qemu
axis -C examples/system build system --target axis:aarch64-qemu --artifact os --jobs 4 --frozen
axis -C examples/system run --target aarch64-qemu
axis -C examples/system logs
-C or --directory selects the project search location. Otherwise discovery starts at the current directory and stops at the nearest enclosing axis.lua. Names do not change with the caller’s working directory.
build constructs the selected product and requires --target. plan inspects the selected graph without executing construction handlers. logs copies the recorded log and starts no construction. When --target is supplied and the project declares exactly one OS product, omitting the product selects that output automatically. Zero or multiple OS products produce an actionable error. Without --target, the command lists available destinations and products without changing the previous build.
The implemented output selector is --artifact os. The current profile is Linux/aarch64 with musl and Docker execution. -j or --jobs supplies a positive total tool-job budget, shared by concurrent phases; it defaults to host CPU count. --jobs 1 serializes construction. --frozen rejects missing or changed pins.
Host installation, general output export and explicit lock-update commands are not implemented. They must not be advertised as successful no-ops.
Running a destination
run [product] --target name performs incremental construction of the image and the selected destination’s support, then launches its declared command on the host with stdin connected. It uses the same source pins, job allocation, frozen policy and verified caches as build. Missing run behavior fails before resolution or construction. A failed build never launches a command. Product selection and destination listing follow the same rules as build.
The project lock spans preparation and the entire process session. Inputs are read-only private file copies, separate from cached results and published images; writable scratch and input copies are removed afterward. The command runs in scratch. Its executable must already be available on the host. This command does not install host tools.
The shipped aarch64-qemu declaration uses qemu-system-aarch64, explicit TCG emulation, a generated kernel and the unmodified image mounted read-only. Its kernel mounts devtmpfs before process entry so the initial process inherits a usable console. The kernel is built in the selected execution service; QEMU runs on the controlling host. QEMU’s Ctrl-a x escape exits its console. Terminal state is restored when the session ends, including cancellation. Nonzero process status and launch failures fail the command.
Only interactive run is implemented; there are no smoke or timeout flags. Successful command preparation does not constitute boot acceptance.
Presentation and logs
Labels preserve the concept being processed and its assigned color. Source acquisition is a phase, not a separate concept: for example, acquired source package: linux retains the package color.
On an interactive terminal, each active phase occupies one lane with elapsed time. Successful completion leaves a green checkmark and completed verb followed by the typed, highlighted name. Failure and cancellation remain distinct.
A positive declared total produces a progress bar. Otherwise an animated indicator shows activity without inventing a percentage. Downloads may report byte totals. Compiler output is not parsed heuristically into progress.
The renderer shows independently running construction phases in concurrent lanes. Each phase receives a share of the global job budget; compiler subprocesses remain inside that phase. Allocations stay fixed until their phase finishes, so the coordinator does not resize an already running compiler when another phase completes.
Build lanes use stderr and a successful image-only construction prints its path on stdout. Before a launch, the animated renderer closes; process stdout and stderr then stream directly to their corresponding terminal streams and the log.
Non-terminal stderr, TERM=dumb and GitHub Actions (GITHUB_ACTIONS=true) use append-only log lines with a UTC timestamp, level (info, done, warn or error), phase and typed name. Activity uses turquoise info; successful completion and cache reuse use green done. Cancellation uses yellow warn and failure uses red error. Completion includes duration; failure includes its diagnostic. Starts omit duration, and intermediate progress updates do not generate lines. --verbose selects this format even on a terminal and also streams tool output to stderr, prefixing each line with a UTC timestamp and info. Split writes receive one prefix per line; an unfinished line is terminated before the next phase transition or renderer close. Verbose image-only construction reports the artifact path as a log line on stderr instead of a bare path on stdout. Ordinary construction output remains in the saved log.
Color is enabled on terminals and in GitHub Actions independently of animation. NO_COLOR or TERM=dumb disables Axis styling. Other redirected output has no ANSI styling. The project’s build/build.log records timestamped phase lines without Axis styling and preserves exact tool bytes, including non-UTF-8 output and any escape sequences emitted by tools. There is no structured replay format.
Internal output identifies its owning phase and element, including input preparation and live tool stdout/stderr. With --verbose, each such line includes a typed phase prefix. Complete tool bytes remain in the saved log.
In GitHub Actions, internal output streams automatically, even without --verbose, into expandable ::group:: / ::endgroup:: blocks named for its phase and element. The renderer closes the current group when output changes owner or a phase transition arrives. Concurrent execution continues unchanged; interleaved output may reopen the same element’s group several times, without nesting unrelated elements or delaying logs until completion. Failed phases emit ::error:: annotations and cancelled phases emit ::warning:: annotations, with the phase, typed name and diagnostic. Annotation data escapes percent signs and line breaks. No source file or line is guessed. Workflow commands are written to stdout and excluded from build.log; NO_COLOR disables styling but keeps this integration. Successful phases remain ordinary done log lines.
Typed labels use the shared palette. The OS concept is labeled os and uses its own palette entry. Presentation observes work without making domain libraries depend on terminal dimensions or ANSI sequences.