Configuration

Settings are layered via pydantic-settings. From lowest to highest precedence:

  1. built-in defaults,

  2. a config file,

  3. environment variables (SHINOBI_*),

  4. explicit CLI overrides.

The model is shinobi.config.AppConfig.

Settings

# ~/.shinobi/config.yml
backend:
  default: native            # default backend when none is specified
  run_as_host_user: true     # docker/podman: run as host uid:gid, not root
execution:
  max_workers: 1             # concurrent recipe steps (1 = sequential)
log:
  dir: "."                   # log output directory
  level: INFO                # log level
  stream: true                # live-echo running cabs' stdout/stderr
cache:
  enabled: false              # step-level result caching, off by default
  dir: ".shinobi/cache"       # cache directory

execution.max_workers defaults to 1: parallelism is opt-in. At 1 the scheduler reproduces exact declaration-order execution and no MUTABLE input can be shared across concurrently-running steps.

backend.run_as_host_user (docker/podman only, default True) adds --user uid:gid plus HOME=<workdir> so bind-mounted outputs come out owned by the invoking host user instead of root. It’s a no-op for apptainer, which already runs as the host user; set it to False for images that need to run as root. See Backends.

log.stream (default True) live-echoes a running cab’s stdout/stderr as it runs (native/container backends only); set to False to restore the old behavior of a silent run followed by one dump of captured output at the end. Overridable per-invocation with ninja run --quiet.

cache.enabled turns on step-level result caching: a step with an unchanged cache key is skipped and its prior result reused. It’s off by default and must also be opted into per-step or per-recipe via Scope.cache – see shinobi.cache. ninja run --cache-dir/--no-cache override this per invocation.

Config file location

By default ninja reads ~/.shinobi/config.yml if it exists. Point it at a different file with the global --config option:

$ ninja --config ./my-config.yml run myrecipe.py:selfcal --ms data.ms

Environment variables

Every setting can be overridden with a SHINOBI_-prefixed environment variable. Nested fields use a double-underscore delimiter:

$ export SHINOBI_BACKEND__DEFAULT=docker
$ export SHINOBI_EXECUTION__MAX_WORKERS=4
$ export SHINOBI_LOG__LEVEL=DEBUG

Loading config in Python

from shinobi.config import AppConfig

config = AppConfig.load()                       # defaults + file + env
config = AppConfig.load("my-config.yml")        # explicit file
config = AppConfig.load(backend={"default": "docker"})  # CLI-style override