Introduction

Part 11

From a sequence to a workflow: let `.lil` make decisions

A linear script is perfect while the answer is always “do A, then B, then C”. The moment you need to ask whether a directory exists, reuse a path, capture a result or stop with a meaningful reason, you are writing a workflow rather than a list.

Use the smallest automation language that fits the job

A file that begins with #lil belongs to the Core linear runner: ordinary commands execute in order, and that simplicity is a feature. It is ideal for setup lists, repeatable diagnostics and short procedures.

run is the next layer. It adds variables, conditions, captured output, nested scripts and explicit failure policy. Do not rewrite every three-line recipe as a program; move to run when the workflow genuinely needs state or decisions.

install run
help run

Variables turn copied paths into named intent

set root lil-playground gives a path a role. Later $root, $source and $archive say what the values mean instead of forcing you to edit the same literal in five places.

Good variable names make a script portable. Keep environment-specific values near the top, keep secrets out, and prefer a few clear variables over clever string construction.

Start the file with this
set root lil-playground
set source lil-playground/project
set archive lil-playground/project.zip

A condition should protect an assumption

if dir "$source" is not decoration: it prevents the archive step from silently operating on the wrong target. Conditions are most valuable around assumptions that would otherwise become destructive or confusing failures.

run supports exists, file, dir, empty, eq, ne, ok, fail and command, with not for inversion. Keep branches short enough that a reader can still understand why each path exists.

Start the file with this
if dir "$source"
    stat "$source"
else
    stop "Project directory is missing"
end

Capture output when the next decision depends on it

capture name <command> executes an ordinary lil command and stores its plain result in a variable. Built-ins such as $last, $status, $cwd and $line expose common execution state.

Do not capture everything just because you can. Captured terminal text is useful when it is small and stable; structured files or dedicated format commands are better when data needs to survive across tools or over time.

Start the file with this
capture current pwd -s
if empty "$current"
    stop "Current directory is unavailable"
end

Decide what failure means before you automate

The default run behavior is fail-fast: a failed command stops the workflow. -k continues after failures and belongs only in jobs where independent steps are truly safe to continue. stop lets the script fail with a reason that makes sense to a human.

Run unfamiliar workflows with -n first. Dry-run validates and expands commands without executing them; -v then shows complete output during a real run. Preview is not bureaucracy — it is how automation stays understandable.

run workflow.lil -n
run workflow.lil -v

Split large workflows by responsibility, not by line count

A workflow can run child.lil in the same variable context, so backup, validation or deployment routines can stay independent and reusable. Keep nesting shallow and give each file one purpose.

run -p creates a checksum-protected compressed representation for transport. Packed .lil is not encryption: it protects format and integrity against accidental edits, not confidentiality or authorship.

run -p workflow.lil workflow.packed.lil
run workflow.packed.lil

Automation intentionally has fewer privileges than an interactive human

Interactive UI commands are blocked in ordinary workflows, and privileged non-interactive commands such as php and ses require explicit -x. The interactive @command auto-install convenience is also rejected inside run scripts.

That friction is deliberate. A reproducible workflow should declare its module dependencies before execution and should not unexpectedly install code, prompt for secrets or destroy the terminal halfway through a run.

Keep this as a script

Save this as workflow.lil, create a lil-playground/project directory if you want the success path, and run it first with run workflow.lil -n. The script demonstrates the important transition: it checks its assumptions before creating the archive.

set root lil-playground
set source lil-playground/project
set archive lil-playground/project.zip

if not dir "$root"
    stop "lil-playground is missing"
end

if dir "$source"
    capture current pwd -s
    zip "$source" "$archive" -f
    stat "$archive"
else
    stop "Project directory is missing"
end