Skip to content

Command Palette

Search for a command to run...

Build intelligence

Matrix runs

Run IDs, live status, retries, resume, and release manifests.

Matrix Run IDs

Every matrix execution gets a Matrix Run ID (mx_20260909_8f31) - printed during the build, recorded in builds/matrix/report.json (run_id), attached to each artifact in versions.json (matrix_run_id), and persisted locally under ~/.phelix/matrix/runs/. The run snapshots the effective configuration at execution time, so later phelix.yaml edits never rewrite what an old run says it built.

List, show, and status

Terminal
phelix matrix list                 # recorded runs, newest first (--limit N caps the list; default 20, 0 = all)phelix matrix list --json          # machine-readable summariesphelix matrix show mx_20260909_8f31        # config snapshot + per-combination resultsphelix matrix show mx_20260909_8f31 --jsonphelix matrix status               # live state of the active run (or "No active Matrix Run.")phelix matrix status mx_20260909_8f31      # a specific run's statephelix matrix status --json        # machine-readable current statephelix matrix retry mx_20260909_8f31 --failed   # retry a run's failures in a new linked runphelix matrix init                 # interactive wizard → writes phelix.yaml

matrix show displays the configuration snapshot (with each dimension's origin: cli, phelix.yaml, or default, plus the effective include/exclude rules and retry budget), every combination's status, duration, attempt history, artifact, SHA-256, and redacted error details for failures. An unknown run ID is a clean NOT_FOUND error. Local run history can be relocated with PHELIX_DATA_DIR like all Phelix state.

Run statuses: succeeded (everything passed), partial (some passed, some failed), failed (nothing passed), interrupted (stopped with incomplete combinations - resumable). A run with failures never reports succeeded.

matrix status answers what is happening right now - unlike matrix list (all recorded runs) and matrix show (full inspection of one run). With no argument it selects the active run: a run whose persisted status is running and whose execution lock is held by a live process. When several runs execute concurrently, the most recently started one is shown (with a note); name a run explicitly to inspect another. If nothing is executing it prints No active Matrix Run. and points at the most recent run - never a fabricated status.

Live status
Matrix Run mx_20260910_4613 - myapp (go)Status:      running - executing (PID 3372540)Started:     2026-09-10 01:49:03 4 combination(s)──────────────────────────────────────────────  ✓ go1.27-linux-amd64                  231ms      Binary: 5621907 B      SHA256: 3263d01d02d8…  ⟳ go1.27-darwin-arm64                 7.2s  ◌ go1.27-linux-arm64                  pending  ◌ go1.27-windows-amd64                pending──────────────────────────────────────────────Progress: 1/4 - success 1 · failed 0 · running 1 · pending 2
  • Live state comes from the same persisted run records the execution engine writes - after every attempt start and every completed combination. There is no second status system that could drift.
  • --json always emits JSON: {"active": false} (plus most_recent_run when any history exists) when nothing is executing - never human text on the JSON stream.
  • Running combinations show elapsed time (duration only - the build engine has no percentage to report) and the in-flight attempt when automatic retries are configured (attempt 2/3). Completed combinations show their final attempt count.
  • Counters are always internally consistent: success + failed + running + pending + skipped = total.
  • A persisted running run whose executing process is gone (crash, SIGKILL, machine restart) is reported as orphaned - resumable, not executing; its in-flight combinations show as stale. A completed run never reports running.

Automatic retries

Terminal
phelix build myapp --matrix --matrix-retries 2

--matrix-retries 2 means two additional attempts (at most 3 executions per combination), not two total. Only failed combinations are retried - a combination that succeeded is never re-executed. Retries happen inside the same Matrix Run: the run records every attempt (Attempts: 3, final: succeeded) in matrix show and report.json, so an eventual success is explainable.

Only transient failures are retried (network, connection, timeout, Docker daemon unavailable); deterministic failures - compiler errors, invalid versions, configuration problems - fail on the first attempt and are not repeated.

Resume

Terminal
phelix build myapp --matrix --resume            # most recent interrupted runphelix build myapp --matrix --resume=mx_20260909_8f31

Resume continues an existing incomplete run instead of starting a new matrix. Runs persist incrementally (after every completed combination), so resume works after Ctrl-C, a crash, or a machine restart. Exact semantics:

  • succeeded combinations → never rebuilt
  • failed combinations → skipped (retry them explicitly with phelix matrix retry <run-id> --failed)
  • pending combinations and running combinations whose worker is gone → executed

Resume uses the run's original configuration snapshot (dimensions, include/exclude rules, build args) - later phelix.yaml edits cannot change what the resumed run builds. Explicit --build-arg flags on the resume invocation are the one exception: they replace the snapshot's build args (and the run record reflects the args actually used). A per-run lock file guards against two concurrent executions of the same run; a lock left by a dead process is reclaimed automatically after a restart. The first Ctrl-C stops the run cleanly (in-flight builds are killed and stay pending); a second one terminates immediately. --matrix-dry-run alongside --resume previews the combinations a resume would execute without touching the run.

Manual retry

Terminal
phelix matrix retry mx_20260909_8f31 --failed

A manual retry creates a new run containing only the combinations whose final status in the source run is failed. The new run records its parent (parent_run_id), executes the source run's configuration snapshot, and the original run's history stays unchanged.

Recovery mechanisms

The three recovery mechanisms are deliberately distinct:

MechanismSame run?What executes
Automatic retry (--matrix-retries)yesfailed combinations, extra attempts
Resume (--resume)yesincomplete combinations only
Manual retry (matrix retry --failed)new linked runfailed combinations of the source run

Interactive wizard: phelix matrix init walks through ecosystem, versions (recent suggestions plus free-form entry), platforms, concurrency, optional include entries (combinations outside the base matrix) and exclusions (picked from the real expanded list), then previews the actual expanded combination list with base/included/excluded counts - never a naive versions × platforms count - before writing the profile. It preserves all unrelated phelix.yaml keys and comments, offers Edit / Keep / Disable / Cancel when a profile already exists, and refuses to run without an interactive terminal (so it never hangs in CI).

Artifact checksums

Every successful matrix artifact carries a SHA-256 checksum computed from the final artifact bytes - streamed, never loaded into memory wholesale. For Docker image artifacts (matrix dockerize), the checksum is the image's content digest (docker image inspect), Docker's own SHA-256 of the image.

Checksums appear:

  • in the build summary and matrix show / matrix status (shortened, e.g. SHA256: 3263d01d02d8...),
  • in full, machine-readably, in builds/matrix/report.json (sha256 per combination), matrix status --json, each artifact row in versions.json (sha256), and the release manifest below.

A checksum that cannot be computed is an artifact-integrity failure: the combination is recorded as failed - an artifact whose bytes cannot be verified is never recorded as a valid release artifact (and integrity failures are never auto-retried). Retries and resume never reuse stale checksums: only the final successful attempt's artifact is checksummed and recorded; resumed runs keep the checksums of previously-succeeded combinations untouched.

Release manifest

Each finished run with successful artifacts also writes a release manifest describing that artifact set, stored next to the run record as <PHELIX_DATA_DIR>/matrix/runs/<run-id>.manifest.json:

mx_20260910_3915.manifest.jsonjson
{  "manifest_version": 1,  "app": "myapp",  "version": 11,  "matrix_run_id": "mx_20260910_3915",  "created_at": "2026-09-10T01:46:38+03:30",  "status": "complete",  "total_combinations": 4,  "language": "go",  "toolchain_versions": ["1.27"],  "platforms": ["linux/amd64", "darwin/arm64", "linux/arm64", "windows/amd64"],  "artifacts": [    {      "combination_id": "go1.27-linux-amd64",      "identity": "mx_20260910_3915/go1.27-linux-amd64",      "toolchain": "go",      "toolchain_version": "1.27",      "platform": "linux/amd64",      "os": "linux",      "arch": "amd64",      "artifact": "builds/matrix/go1.27-linux-amd64/myapp_amd64_go_1.27",      "size_bytes": 2433430,      "sha256": "dfef784b056f..."    }  ]}

Completeness is explicit and fail-closed:

Run outcomeManifest
all combinations succeededwritten, status: "complete"
some succeeded, some failedwritten, status: "partial" (only successful artifacts listed)
nothing succeeded / interrupted / still runningnot written

A partial matrix can therefore never masquerade as a complete release - the status field and the total_combinations count make the gap machine-checkable. Artifacts are sorted by combination ID, so the same run and artifact set always produce the same manifest. matrix show <run-id> renders the release summary (version, status, artifact count, manifest path). An interrupted run gains its manifest only once a --resume finishes it; a manual retry run gets its own manifest - runs are never merged. Docker matrix builds (phelix dockerize --matrix) record image digests per artifact in versions.json but produce no run manifest (they are not Matrix Runs).

One release, many artifacts

A matrix build is one logical build/release of one application version that produces multiple artifacts. Matrix combinations are artifacts of that release, never independent application versions: go1.27-linux-amd64, go1.27-linux-arm64, ... are artifact names (and filenames), while versions.json records exactly one version row (vN) carrying all of them:

Release structure
Application    └── Version vN (one versions.json row)            └── Matrix Run mx_...                    └── Artifacts: go1.27-linux-amd64, go1.27-linux-arm64, ...