Checked before it runs
lask check resolves every name, argument and type, and the environment of every command, without running anything. Your editor shows the same errors as you type.
Tasks are typed functions in one file. Their commands run in container images pinned by digest, the same on your laptop and in CI, and never on the host unless the file says so.
Lask in one minute, in five steps: try a command in the REPL, keep it as a task, run it, run the same thing on a laptop and in CI, and keep secrets in Vault.
A main.lask that lints and tests a Python project, with neither Python nor the linter installed:
// Each program comes from a pinned image.
command { "python" } on #python:3.13.7-alpine3.22
command { "ruff" } on #ghcr.io/astral-sh/ruff:0.13.3-alpine
// Lint and test at the same time.
ci() = do {
lint = async $ ruff check app
test = async $ python -m unittest discover -s app
all([lint, test])
}$ lask sync # pull both images and pin their digests in lask.lock.json
$ lask run ci # run both commands, each in its own containerMisspell python as pyhton on line 8, and lask check reports it before anything runs:
$ lask check
main.lask:8:16-8:52: E-TYPE-COMMAND-NOENV [static]: 'pyhton' is not a declared command; ...Your first real task file builds this file step by step.