Status
One read-only view of every node: what it is, whether it is cached and why, when it last ran,
and what its artifact looks like. It answers in one call what would otherwise take barca list,
--dry-run, barca history and a script that opens the artifact.
The experimental disk_usage summary reports project-wide storage across all environments,
even when node selection or filters narrow the graph: budget_bytes, backup_bytes,
physical size_bytes and limit_bytes. Recognized local metadata backups are outside the
cache budget and included in the physical total. Human output shows the same distinction.
Budgeted bytes use the last maintained GC measurement; status does not walk artifacts or
refresh that measurement. Backup directories are checked directly with a bounded survey
(at most 4096 directory entries across environments and backup files). Unmeasured counts,
including an incomplete backup survey, are null and displayed as unmeasured. Use barca doctor or barca gc --dry-run for a full measurement. Server status reports server storage.
The UI’s /state node array does no additional disk-accounting work.
Status inspection reuses bounded evidence instead of re-reading unchanged artifact bytes. Local file identities include device, inode, size, mtime and ctime; changed or missing local copies and directory-store objects are checked again immediately. Cloud availability and remote shape observations can be up to five minutes old; cache hits do not extend that window. Local materialization changes, confirmed transfers, credential changes and Python import-environment changes invalidate the affected evidence. Inspection prefers an already verified local copy for shape. This is availability and shape evidence, not a new freshness proof. Required reads, transfers and server ledger publication keep their direct verification paths.
Local inspection evidence is reusable only after the file’s change timestamp is at least one second old. Recently changed files are read directly without retaining evidence, so inode reuse within a filesystem timestamp tick cannot preserve an old observation.
The disposable inspection cache is limited to 8 MiB and 8192 entries per environment, with at most 64 KiB per value. Corruption, eviction or an unwritable cache causes another check; a busy cache-write lock is skipped. Cold inspection still hashes selected local copies and plain-directory store objects once, so its cost grows with their bytes. These limits do not resolve the broader cold/per-key planning and inspection gaps (#655 and #656).
import pandas as pdfrom barca import asset, task
@asset()def orders() -> pd.DataFrame: return pd.DataFrame({"id": [1, 2, 3], "amount": [9.5, 3.0, 12.25]})
@asset(inputs={"df": orders})def total(df: pd.DataFrame) -> dict: return {"total": float(df["amount"].sum())}
@task(inputs={"t": total})def notify(t: dict) -> None: print(t)barca get total pipeline.pybarca status pipeline.py --pretty # table (the default in a terminal)barca status total pipeline.py # only `total` and its upstream conebarca status total,notify pipeline.py # several targets: the union of their conesbarca status pipeline.py --json # one JSON document (the default when piped)barca status pipeline.py --fields id,cache # JSON with only these keys per nodebarca status pipeline.py --json --sample 2 # plus up to 2 sample rows per json/parquet artifactbarca status pipeline.py --problems # only the nodes that need attention (below)barca status pipeline.py --state stale,never_run # only nodes in these cache statesNAME KIND STATE WHY LAST RUN SHAPE DEPSorders asset cached materialized success 2026-10-02 11:56:43 UTC 0.54s 3 rows x 2 cols -total asset cached materialized success 2026-10-02 11:56:43 UTC 0.00s dict (1 key) ordersnotify task always-runs task - - total
2 cached, 0 stale, 0 never run, 0 partial, 0 unknown, 1 always runStatus executes no pipeline step and records no new run, and it does not create .barca/.
Source parsing is static, but partitions(<expression>) may evaluate Python and import its
module while resolving keys. Times in the table (LAST RUN, like STARTED in barca history
and CREATED in barca stats) are UTC and say so; the JSON has the same UTC values. Like every inspection command, the result goes to stdout (a table in a terminal, JSON
when piped; --json / --pretty override) and errors to stderr; an unknown target is a usage
error (exit 2) that ends with Run `barca list <files>` to see available assets and tasks.,
the same remediation as get and run. A target is one name or several, comma-separated with no
spaces (a,b), parsed exactly as get and run parse them; the JSON names them in targets
(and the single one in target).
With an artifact store (barca docs remote), status also asks the store about every cached
unpartitioned node, with one python -m barca._state stat for all of them, and reports a node
whose copies do not agree as unsynced (below). Nothing is downloaded or uploaded.
Status reads the metadata DB as it is at that moment, and a run records each step as it
finishes. So while a barca get is running, status in another terminal already shows the steps
it has finished as cached (a partitioned asset as partial, with counts); see barca docs layout, “While a run is going, and after one is killed”.
Like list, status returns every node in JSON unless --limit N is explicit. The human
table shows at most 100 nodes unless you pass --limit N or --all. The
summary still counts every node, and the JSON adds total and truncated (with a hint when
truncated). Each node also lists env, the environment variables it declares with env=[...]
(barca docs assets), and, when its code reads variables it does not declare, undeclared_env
(experimental; barca docs cache, “Environment variables”). --fields keeps only the named keys
on each node.
Cache state
Section titled “Cache state”cache.state is the same decision barca get --dry-run makes (both call one function), so the
two cannot disagree. In JSON the states are snake_case, spelled exactly like the summary keys
(never_run, always_runs); the table prints them as never-run and always-runs.
| state | meaning | reason |
|---|---|---|
cached |
a successful result matches this code and these inputs; get serves it |
materialized |
unsynced |
cached, but not where it should be: with an artifact store, this machine’s copy, the store’s object and the recorded digest do not all agree (barca docs remote, “cached and unsynced with a store”), and get on it repairs that without running a step; with a configured server, the server has no result but this machine computed one whose post to the server’s ledger is pending (barca docs server-mode) |
local_only, store_only, mismatch, not_in_ledger (the table prints local only, store only, mismatch, not in ledger) |
stale |
it ran before, but get would run it again |
changed, upstream_stale, failed, artifact_missing, evicted |
never_run |
no successful materialization is recorded | no_record, failed |
partial |
a partitioned asset with some keys cached | partitions_missing |
blocked |
a partitioned asset whose missing keys wait on the same keys of an input, which failed: a run computes its other keys and skips these (barca docs partitions, “Failed keys block their own keys”) |
upstream_failed (detail: 39 of 39 missing keys wait on 'demand_forecast': the same keys of it failed) |
unknown |
dynamic partitions (partitions_from) whose source has not run yet, an asset reading a sensor with no recorded output, or an asset reading an @asset(cutoff=True) that would run first (and what depends on any of them); not_planned when the dry run status is computed from has no step for the node |
partitions_unknown, sensor_output_unknown, cutoff_pending, not_planned |
always_runs |
tasks and sensors are never cached | task, sensor |
-
cache.change_causes(on astalenode, and a failed one that once succeeded) sorts the same evidence by cause:code_changed,inputs_changed,env_changed,upstream_stale. It is absent when the last success recorded no components.cache.reasonkeeps its values. -
changed: the run hash differs from the last successful materialization.cache.changedlists what differs, anddetailand the table’s WHY column name the first and count the rest (changed: helper pipelines/common.py:bucket_ltv (+1 more)):entry what changed codethe function, from defondecorator argument NAMEan argument of @asset/@sensor/@taskthat counts (serializer,inputs, …;barca docs cache)decorator NAMEanother decorator that counts ( @sink,@functools.lru_cache, …)helper FILE:NAMEa definition the function uses, in its own file or a project module ( pipelines/common.py:bucket_ltv);helper FILEfor a module it uses wholeinput IDan upstream’s run hash: its code or its own inputs changed sensor IDa sensor it reads returned a new value (or its code changed) value IDa dict partitions_fromsource returned a new value for this key (or its code changed;barca docs partitions)env NAMEa declared environment variable’s value kindthe node became an asset, task or sensor An entry appears when it was added or removed too (a helper the function now uses). Each materialization records a short digest of each of these; a result recorded by barca before 0.29.0 has none, and the node is then a plain
changedwith nocache.changed. Astalenode with reasonupstream_stalecarriescache.changedas well when it can be told. -
A node that reads a
@sensoris judged by the sensor’s last recorded output: status runs nothing, so it assumes the sensor returns the same value next time, anddetailsays so. If the sensor recorded a new value since the node last ran (for example a scheduled sensor), the node shows asstale(barca docs cache, “External data that changes in place”). -
A
partialnode’spartitionshaschanged(experimental) when a key ofmissing_keysran before: key -> what changed in its run hash, in the entries above. A new key has no entry. With keys from a dict sensor,{"retailer=r2": ["value pipeline.py:versions"]}says the sensor returned a new value for that retailer. -
upstream_stale: an input is itself not cached, so this node’s inputs will change when it runs.detailnames the input. -
failed: the last attempt at exactly this code and these inputs raised;detailcarries the message. -
artifact_missing: the result is recorded and its run hash is unchanged, but the artifact file is gone and a run over these nodes would have to read it (a step that runs takes it as an input, or it is the output the run returns: a target, or with no target the last asset), so it would be computed again. A missing artifact that nothing would read does not make a node stale: it stayscached, andcache.artifactthen names a file that is not there (barca docs cache, “A cached result whose artifact is missing”). -
evicted: the same, because the cache size limit deleted the artifact file (barca docs disk). A result the artifact store holds is not stale: a run downloads it again. -
local_only,store_only,mismatch: only with an artifact store.local_only: the result is on this machine and not in the store, or its upload is pending (detailthen carries the upload’s last error); the nextgetorrunuploads it.store_only: in the store, not on this machine;getfetches it.mismatch: both copies are there and differ in size (or in bytes, for a store that is a plain directory), or this machine’s copy is not the one recorded. When this machine’s copy is the recorded one,getuploads it again, with the changed-bytes warning; otherwisegetfetches the store’s copy, warns once and records its digest, so the result iscachedafterwards (barca docs remote). A result in neither place isstalewithartifact_missing. Object stores give no checksum, so a same-size object with other bytes is not noticed there. A partitioned asset isunsynced(local_only) only when one of its keys has a pending upload. A store that cannot be asked leaves the state as it is, with a note indetail. The summary line counts these nodes (1 cached, 1 unsynced, 0 stale, ...) andsummary.unsyncedis always present.
cache.run_hash is the cache key for the current code and inputs; cache.artifact is the file a
get would serve (only when cached or unsynced).
With a server configured
Section titled “With a server configured”With BARCA_SERVER or [server] url set, barca status (without --server or --local) is
answered by the server’s ledger for its deployed code, after [barca] server <url> (<source>)
on stderr (barca docs server-mode). Each node gets local: true when this machine has a copy
of the result the server would serve, which is what barca sql can query here. A node the
server has no result for, but whose result this machine computed and has not posted yet (the
post was refused or the server could not be reached), is unsynced with reason not_in_ledger
and local: true; the next get or run against the server posts it. summary.unsynced
counts unsynced nodes. A partitioned node’s local is false (it has no single artifact).
barca status --local shows this machine’s own state.
Finding problems: --problems and --state
Section titled “Finding problems: --problems and --state”--state <state[,state...]> keeps the nodes whose cache.state is one of those named, spelled
as in JSON (never-run is accepted for never_run). An unknown state is a usage error (exit 2)
naming the valid ones; failed is not a state (a failed node is stale or never_run with
reason failed), and the error says to use --problems.
--problems keeps every node that needs attention:
- every state but
cachedandalways_runs:unsynced,stale,never_run,partial,blockedandunknown. A node that never ran counts: nothing it would serve exists yet; - a task or sensor (
always_runs) whose last run failed; - a node whose schedule is paused or failing (below).
A cached node and a task that last succeeded are fine. Given both, a node must pass both
(--problems --state stale is the stale nodes). The filter applies after the targets’ cones and
before --limit; total counts the nodes that passed. The summary still counts every node in
scope, so the counts do not change with the filter, and the JSON names the filter in filter
({"problems": true}, {"states": ["stale"]}); it is absent without one. The table says how many
nodes matched before the summary line, or No node matches --problems. when none did:
barca status --problems --json --fields id,cache,last_materialization,scheduleNAME KIND STATE WHY LAST RUN SHAPE SCHEDULE DEPSnightly_sync task always-runs last run failed: RuntimeError: upstream API returned 503 failed 2026-10-22 22:51:16 UTC - */2 * * * * *; failing 2/2 -prices asset stale changed: code success 2026-10-22 22:51:12 UTC 0.00s dict (1 key) - -ratio asset never-run failed: ZeroDivisionError: division by zero failed 2026-10-22 22:51:12 UTC - - orders
3 of 4 nodes match --problems; the counts below are for every node
1 cached, 1 stale, 1 never run, 0 partial, 0 unknown, 1 always runA node whose last run failed shows the first line of its error in WHY: failed: ZeroDivisionError: division by zero for reason failed, last run failed: ... for a task or
sensor, and <reason>; last run failed: ... otherwise (a cached node is not marked). The whole
message, with the traceback, is last_materialization.error in JSON; barca logs RUN_ID --step NODE --stream stderr has the step’s own stderr.
With a server configured, the server answers and the filter is applied here, after this
machine’s not_in_ledger results are marked, so --state unsynced finds them. GET /nodes?state=stale&problems=1 filters the same way over HTTP.
Schedules
Section titled “Schedules”A node with freshness=Schedule(...) has schedule in JSON (absent on other nodes), and the
table adds a SCHEDULE column when a node it shows is scheduled:
| key | meaning |
|---|---|
cron |
the cron expression |
next_fire |
when it next matches (RFC 3339, UTC) |
last_fired |
the last tick fired (RFC 3339, UTC), or null |
last_status |
the status of the run that tick started, while the server remembers it (null after a restart) |
failures, max_failures, failing |
consecutive failed ticks, Schedule(..., max_failures=N) (default 5), and failures >= max_failures: ticks are skipped (barca docs scheduling) |
paused, paused_until |
held back by POST /schedule/{id}/pause; paused_until is null for a pause until resumed |
skip_reason |
why the last due tick was skipped: in_flight or paused, or null |
live |
true when a running scheduler reported this entry |
The SCHEDULE cell is <cron>; failing 2/2, <cron>; paused (or paused until <time> UTC), or
<cron>; next <time> UTC, with 1 failure, before next while failures are counting.
- From a server (configured, or
--server): the server’s scheduler’s view, the same numbersGET /scheduleand the web UI’s Schedules page show, withnext_firein the server’s--timezone, andlive: true. A server started with--no-scheduleor--read-onlyfires nothing: its entries come from its metadata DB as below, withlive: false. - On this machine (
--local, or no server): no scheduler runs, so the entry is what the metadata DB holds: the failures and pauses abarca serveof this.barca/recorded, and the last tick it fired.next_fireis the next match in this machine’s local time, asbarca listcomputes it.last_statusandskip_reasonarenullandliveisfalse. A laptop that never ranbarca serveshowsfailures: 0andpaused: false.
Last materialization
Section titled “Last materialization”last_materialization is the most recent execution recorded in the metadata DB, successful or
failed: status, created_at (UTC), elapsed_seconds, run_hash, artifact, format,
size_bytes, and error for a failure. A cache hit is not an execution, so serving from cache
does not change it. It is null when the node never ran.
For a partitioned node it is one key’s row from the latest run, the first key in sort order
(partition names it), so two identical runs report the same key whatever order the keys
finished in.
Last changed bytes
Section titled “Last changed bytes”last_bytes_change is the most recent recompute of the node that produced different bytes for
the same code and inputs (the same run hash): {node_id, run_hash, content_hash, created_at},
with the exact node id (a partition key included). It is absent when that never happened. The
table prints one line per such node under the rows:
total: different bytes for the same code and inputs at 2026-10-02 11:56:43 UTC (pipeline.py:total).
It means the function is not deterministic (barca docs cache).
Artifact shape
Section titled “Artifact shape”shape describes the artifact of last_materialization when that run succeeded (null
otherwise). It is read from the file alone by a small Python helper; your modules are never
imported.
| format | shape |
|---|---|
| parquet | type: "table", rows, columns: [{name, type}] (arrow types) from the file footer |
| json list | type: "list", rows; for a list of objects also columns with the JSON types seen (str | null) |
| json object | type: "dict", keys (first 100; key_count when there are more) |
| other json | type (int, str, …) |
| pickle | type only, e.g. myproject.Model, read from the pickle opcodes without unpickling |
--sample N adds sample: the first N rows (parquet, json list), the first N entries (json
object), or the value (other json). It is off by default to keep output small. Pickles are never
sampled: loading one would import and run code.
When the shape cannot be read, shape has a note instead of rows/columns: parquet without
pyarrow installed (pip install 'barca[parquet]'), a file that no longer exists, or a remote
artifact that is too large or cannot be reached (below).
Remote artifacts
Section titled “Remote artifacts”With remote storage (barca docs remote) the shape is read from the bucket, through the same
filesystem, credentials and [remote.storage_options.*] the steps use. There is no flag for it:
barca status total --json --sample 2 # rows, columns and 2 sample rows, read from the bucket- parquet:
rowsandcolumnscome from the file footer by ranged requests; the object is not downloaded.--sample Nalso reads the first row group, not the whole file. Measured on a 160 MB file of 20 row groups in S3-compatible storage: 64 KB read for the shape, 8 to 9 MB with--sample 5. - json and pickle have to be downloaded to be described, so only objects up to 16 MB are. A
larger one has
"note": "remote json artifact too large to inspect: 25.1 MB (limit 16 MB)".barca sqlcan still query a large json result.
Each node with a result costs one or two requests, and up to 8 artifacts are read at a time.
barca status with no target reads every node; name a target to read only its upstream cone.
A store that cannot be read never fails the command. A missing driver
(pip install 'barca[s3]'), rejected credentials or a network error is the note of each
shape, the rest of the status is complete, and the exit code is 0. After the first such failure
the artifacts not yet read report it without another attempt, so an unreachable bucket costs one
wait for the driver’s retries (about 10 seconds for an S3 endpoint that refuses connections),
not one per node.
Partitioned assets
Section titled “Partitioned assets”A partitioned asset is one node with a partitions summary: total, cached, missing and up
to 20 missing_keys. Its state is cached when every key is, partial when some are, and
stale/never_run when none are. last_materialization is one key of the latest run (the first in
sort order), named in its partition field (for example k=a), and shape describes that one key’s artifact.
{ "target": "total", "targets": ["total"], "nodes": [ { "id": "pipeline.py:orders", "name": "orders", "kind": "asset", "inputs": [], "partitioned": false, "cache": {"state": "cached", "reason": "materialized", "detail": "...", "run_hash": "6db9...", "artifact": ".barca/artifacts/pipeline.py--orders/6db9....parquet"}, "last_materialization": {"status": "success", "created_at": "2026-10-02 11:56:43", "elapsed_seconds": 0.54, "run_hash": "6db9...", "artifact": ".barca/artifacts/pipeline.py--orders/6db9....parquet", "format": "parquet", "size_bytes": 2182}, "shape": {"type": "table", "rows": 3, "columns": [{"name": "id", "type": "int64"}, {"name": "amount", "type": "double"}]} } ], "summary": {"cached": 2, "unsynced": 0, "stale": 0, "never_run": 0, "partial": 0, "blocked": 0, "unknown": 0, "always_runs": 0}}A scheduled node adds "schedule": {"cron": "0 6 * * *", "next_fire": "2026-10-23T06:00:00Z", "last_fired": null, "last_status": null, "failures": 0, "max_failures": 5, "failing": false, "paused": false, "paused_until": null, "skip_reason": null, "live": false}, and --state or
--problems add "filter" beside summary.
Keys inside a sample row are printed in alphabetical order; columns keeps the file’s column
order. --env <name> reads another environment’s state (barca docs cache).
An explicit @asset(name="orders_clean") uses orders_clean in status and as its SQL
view name, matching list, get and stats. Inspection reads the existing artifact
without importing or rerunning its producer.
Run timing and attempts
Section titled “Run timing and attempts”get --json and run --json add elapsed_seconds and attempts to executed steps,
including failed steps. Cached steps and dry runs omit them. Elapsed time sums active
worker time across attempts: module import, input loading, the call and artifact
serialization; retry backoff is excluded. After a worker disconnect, elapsed time falls
back to the coordinator’s observed in-flight time. For a partitioned step, elapsed time
sums its executed keys (and can exceed run wall time); attempts is the maximum for any
one key, not the number of keys.
barca get total pipeline.py --json --fields id,status,elapsed_seconds,attempts,import_secondsbarca history --json --fields run_id,status,attemptsbarca stats total pipeline.py --jsonUnder --agent (and in every run barca serve starts), a worker prints
[barca] importing <module> on stderr before it imports a module; without --agent it prints
nothing of its own, and the import time is in the run JSON. Imports longer than one second add import_seconds to the step report, summed across
attempts and executed keys. This time is included in elapsed_seconds; it is not an
extra charge. A reused module adds no import time. Framework import diagnostics remain
visible under --json; task prints remain accessible through barca logs.
--agent completion and final failure lines append attempts=N when N exceeds one.
Completion lines retain their existing final-attempt duration. history --json adds
attempts, the total attempts in recorded materialization rows (zero for an all-cached
run; upload-failure rows from earlier versions retain their transfer-attempt counts). stats shows
attempts per recorded materialization and its stored final-attempt duration. For a partitioned
node (barca stats scored) an execution is a run: total_runs counts runs, elapsed_seconds and
cpu_seconds sum its keys, and each recent_runs entry adds keys and failed_keys.
Timeout errors name the step id, including its partition key.
Older read-only snapshots without attempt metadata report a null history attempt total.
What started a run
Section titled “What started a run”barca history --json rows carry triggered_by: manual for a command typed on a machine
(barca get, barca run), api for a run started over HTTP on barca serve, schedule for a
cron tick, and client for a run a laptop posted to a server’s ledger. A scheduled run also
carries the tick it was started for in scheduled_at (RFC 3339, UTC) and the scheduled node in
schedule_id; both are null otherwise. Runs recorded before barca recorded this have
triggered_by: null.
barca history --json --fields run_id,triggered_by,scheduled_at,schedule_idFinding and reading a failed run
Section titled “Finding and reading a failed run”barca history filters its runs; the filters combine with AND, and --limit, total and
truncated count the runs they keep:
--status success,failed,...: any ofsuccess,failed,cancelled,error,running,interrupted.--target NAME: runs whose target (as typed) or job (resolved node ids) is that node, by function name or node id. A run of every node (all) is left out.--triggered-by manual,api,schedule,client.--since WHEN: started at or after a duration back from now (30m,24h,7d,2w), an RFC 3339 time or a UTC date (2026-10-22).
A failed run’s row ends with its first failed step and the first line of its error, and JSON
carries it as failure: {node, error} and again as the flat failed_node and error (null
for every other run, and for a run that failed before any step did, such as a file that does
not parse), so --fields run_id,failed_node,error needs no nesting.
barca history --status failed --since 24hbarca history --status failed --target clean --json --fields run_id,started_at,failurebarca history --status failed --json --fields run_id,failed_node,errorbarca history --triggered-by schedule --status failed,interruptedbarca history RUN_ID shows one run: its own fields (status, target, job, timing, attempts,
what started it, the schedule tick and client_run_id when it has them), then each step it
recorded with its status, attempts, time, peak memory (PEAK_RSS), run hash and artifact
(path, format and size), then each failed step’s error, its full traceback, when its worker
died how the process ended (worker exit: SIGKILL (possibly the OOM killer), another signal,
an exit code), and the last 20 lines the step printed before it failed (stdout and stderr in
the order they were written, without the traceback). A hint on stderr names the command that
prints all of the failed step’s stderr. JSON is {run, steps, hint?}: run is the run as
barca history --json lists it, and each step has node_id, partition_key, status
(success or failed), attempts, elapsed_seconds, cpu_seconds, max_rss_bytes,
run_hash, artifact_path, artifact_format, artifact_size_bytes, error (as recorded),
error_type, error_message, error_traceback, error_phase (where it failed: user_code,
or barca’s own load_inputs, split_output, write_output or sink; null when unknown),
worker_exit and output_tail (a failed step’s last lines, null for the others). A step that
failed in barca’s own code says so: p.py:clean failed in barca while writing its result (phase write_output): ..., followed by a traceback that keeps barca’s frames.
max_rss_bytes is the peak resident memory of the worker process while the step ran, from the
start of the step to the end of writing its result, so a returned DuckDB relation that does
its work while it is written is counted. It includes what the worker already held (Python,
imported modules, a DuckDB connection’s buffers). On Linux each step’s peak is its own (barca
resets the kernel’s peak counter, VmHWM, when a step starts); elsewhere it is known only for
a step that raised the worker’s peak, and is null otherwise. A failed step has none. Rows
recorded before 0.31 hold the worker’s peak over every step it had run, not the step’s own.
Bytes DuckDB spilled to disk are not recorded: DuckDB keeps no total or peak of them, and its
temporary files are gone when the query ends, so only sampling during the step could find
them.
barca history 7f30b3e9barca history 7f30b3e9 --jsonbarca logs 7f30b3e9 --step clean --stream stderrReplace the example id with a run_id from barca history. Only the steps a run executed or
that failed are listed: cached steps are counted in the run’s steps_cached (they recorded no
new row), and steps a failure skipped are not recorded. With a server configured, both forms
answer from the server (barca docs server-mode); a run id only this machine has is an error
whose remediation is barca history RUN_ID --local.
See also: barca docs cache, barca docs logs, barca docs sql, barca docs agents.