Query Tasks
Use filters to find unfinished work, inspect failures or outliers, and update a selected group of Tasks. Task list, count, and bulk update share the same small expression language, so a selection can be checked before it is changed.
Queries never decide which Worker may run a Task. Worker compatibility is set only through routes.
priority >= 10 and metadata.group == "ablation"
"baseline" in metadata.tags
status == "failed" and last_error.type == "ValueError"
missing(result.score) or result.score < 0.9
Values and paths
Literals use Python spelling: strings, integers, floats, True, False, and
None. A path starts at the Task representation and traverses JSON objects with
dots, such as metadata.benchmark or result.metrics.f1.
Supported top-level fields include id, name, status, args, metadata,
priority, attempt, max_attempts, routes, result, last_error,
last_route, and Task timestamps.
Operators
== != < <= > >=
in not in
and or
Parentheses control grouping. in is explicit about direction:
status in ["failed", "cancelled"]
"sdxl-v2" in routes
path in [value, ...] checks a scalar against a candidate list.
value in path checks whether an array-valued path contains that value. It does
not test object keys: use exists(metadata.owner) for that. General unary
not (...) is unsupported; use !=, not in, exists, or missing instead.
Missing values
Ordinary comparisons require a path to exist. Missing data does not silently
behave like null or false. State the intended behavior:
exists(metadata.owner)
missing(metadata.owner)
missing(result.score) or result.score < 0.5
exists(path) and missing(path) are the only path-existence tests.
Ordering and pagination
List queries choose one stable order field and direction:
labtasker task list \
--filter 'status == "pending"' \
--order-by priority \
--descending \
--limit 100
The Server adds Task ID as a deterministic tie-breaker. A cursor must be reused with the same Queue, filter, selectors, order field, and direction.