Cabs¶
A Cab is a typed, backend-agnostic description of an atomic
task – a single command with an inputs/outputs schema and policies for
turning parameters into a CLI invocation. It is the fundamental unit of work: a
recipe is just cabs (and other steps) wired together.
Defining a cab in Python¶
A cab needs a name, the command to run, and pydantic models describing
its inputs and outputs. An optional image names the container the command
lives in (used by the container/cluster backends).
from pydantic import BaseModel
from shinobi import Cab
class ImageInputs(BaseModel):
ms: str = "obs.ms"
prefix: str = "img"
class ImageOutputs(BaseModel):
restored: str | None = None
wsclean = Cab(
name="wsclean",
command="wsclean",
image="quay.io/stimela/wsclean:latest",
inputs_model=ImageInputs,
outputs_model=ImageOutputs,
)
Fields with a default are optional; fields without one are required. The dtype comes from the type hint.
Building models from a compact spec¶
Hand-writing a pydantic model per cab is verbose. The same helper the YAML
loaders use, shinobi.loaders.build_model(), builds one from a
{name: (dtype, required, default)} mapping:
from shinobi.loaders import build_model
inputs = build_model("MaskInputs", {"restored_image": ("File", True, None)})
outputs = build_model("MaskOutputs", {"mask": ("File", False, None)})
File and MS dtypes are meaningful beyond typing: the container and
cluster backends inspect them to decide which paths to bind-mount.
Turning parameters into argv¶
How a cab’s parameters become command-line arguments is controlled by its
policies and per-field field_meta. For example, mark a parameter as
positional (passed as a bare argument rather than --flag value) with a
ParamMeta:
from shinobi.steps import ParamMeta
touch = Cab(
name="make",
command="/bin/touch",
inputs_model=build_model("TouchInputs", {"out": ("File", True, None)}),
outputs_model=build_model("PathOutputs", {"out": ("File", False, None)}),
field_meta={"out": ParamMeta(positional=True)},
)
See shinobi.Cab and shinobi.steps.schema.Policies in the
API reference for the full set of knobs (prefixes,
repeat policies, nom_de_guerre renaming, input patterns, and output
wranglers).
Loading cabs from YAML¶
You do not have to define cabs in Python. Existing cult-cargo YAML is loaded as-is – see Loaders.
Inspecting a cab¶
The ninja cab command dumps a loaded cab’s resolved schema as JSON, which
is handy for checking how a YAML definition was interpreted:
$ ninja cab cabs.yml wsclean
To look a cab up by name across installed shinobi.cabs providers (e.g.
dosho) instead of pointing at
a specific YAML file, use ninja cabs show/ninja cabs list:
$ ninja cabs list
$ ninja cabs show wsclean