A declarative, YAML-driven job runner. A sortie is a list of steps; each
step names an action (a reusable building block) and the args to call it
with. Steps share a context — an action stores its result under as:, later
steps read it with <<dot.path>> interpolation. A when: shape gates a step on
accumulated state. The CLI (bin/drone run SORTIE.yml) loads a sortie and runs
it; the engine is generic, the specifics live entirely in the YAML.
"If Unix pipes and PowerShell had a baby and it was only the good parts." — the design goal, said better than the docs could.
name: example
params:
core: { values: [ars-dih, ars-suggester], required: true }
state: tmp/example.state.yml # opt-in resume
maneuvers:
watch: # a reusable step-chain
- { action: run_on_remote, as: poll, with: {...} }
- { action: ruby, as: prog, with: { ..., code: "..." } }
- { action: print, with: { text: "<<params.core>> <<prog>>" } }
steps:
- { action: aws, as: bastion, with: {...} }
- action: loop # repeat a maneuver until a shape matches
with: { maneuver: watch, until: { poll: { json: { status: idle } } }, every: 15, max: 480 }
aws (CLI or SDK, auto-paginate), run_on_remote (ssh / eic / ssm / ecs —
the bastion path), psql (first-class DB, numeric-coerced rows), tunnel
(self-contained SSM port-forward up/down), shell, http_request,
oauth_login, browser (Playwright HAR), fetch_cloudwatch_logs, read_file,
verify (assert via ShapeMatcher), extract / select / query (JMESPath),
ruby (eval a snippet — args as locals + args hash + ctx; the escape
hatch for arithmetic/reshaping without shelling out), template (ERB),
print, prompt (typed confirm / select), sleep, run / loop / foreach
/ map (control flow; map fans out concurrently).
loop/map — chain small actions and repeat them. The
poll-until-idle pattern (run a status action, compute a progress line, repeat
until a shape matches) recurs everywhere — see advaita-solr-cores-rebuild-runbook.required: true refuses to run without
them; referenced as <<params.name>>.state: + resume — a singular sortie records each completed step; a
re-run skips proven steps and rehydrates their output (so <<...>> still
resolves), and a disconnect mid-job re-attaches by polling rather than
re-firing. always: true on a step forces re-run (ephemeral setup like a
tunnel). The state file doubles as the observability surface — monitoring
is just reading it.!Env, !SSMLookup) resolve once at load; loop
phase (!PickFrom, !Context, !Sub, <<...>>) resolve per iteration.verify (assert),
when: (branch), and loop's until: (poll). The unification that makes it
not-a-toy.Operations, not builds. The trace/audit is a dial: a monitor needs none (the state file suffices); a prod mutation turns it up. The launcher that runs sorties as services — triggered, persisted, OAuth-gated — is vivarta-airfield (west of it: the heavyweight, fully-audited vivarta / Jenkins pipeline tier).