A compiled language asks a small ceremony of you: compile, then link, then run what was linked. The ceremony earns its keep for programs you ship — and gets in the way for the other kind of program: the ten-line tool, the quick check, the file you write to think. For those, people reach for a scripting language, and trade away every compile-time guarantee to save one command.

The next Mica release removes the trade:

mica --run tool.mica

One command compiles the file, links it, runs it, and cleans up after itself. No build directory beside your file, no cache in your home directory, no state anywhere. A Mica debug compile of a single file is a matter of milliseconds — a hello-world round trip, compile and run, finishes in about a hundredth of a second — so the mode simply recompiles every time. The fastest cache is the one you don’t need.

The scripting conventions, all of them

A script runner earns its name on conventions, not on speed. --run follows the ones every shell user already knows:

Everything after the file belongs to the program. Arguments land in the process unit’s ArgCount and Arg, and an optional -- separator is accepted where a program’s own arguments begin with a dash:

$ mica --run args.mica alpha beta
count=2
first=alpha
second=beta

The program’s exit code is the exit code. Shell callers branch on $?; under --run they see the program’s own verdict, including a runtime failure’s non-zero exit.

The program owns standard output. On a clean compile the compiler prints nothing at all — no banner, no progress, nothing to strip before piping. Diagnostics, when there are any, arrive on standard error; warnings survive the silence rule, because a warning you never see does not exist.

A here-document is a program. --run - reads the source from standard input:

mica --run - << 'EOF'
program Hi; imp WriteLn : std; begin WriteLn("hi"); end.
EOF

Shebang, and then some. A leading #! line belongs to the operating system, and the compiler’s source preparation removes it on every road — line numbers stay true, and the editor accepts the file exactly as the kernel does, with no diagnostic on the addressing line. The bare spelling mica tool.mica means the same as --run tool.mica, which makes

#!/usr/bin/env mica

a working first line on every Unix, without the GNU-only env -S trick that multi-word interpreters normally require. chmod +x tool.mica, and the file is a command — and the bare spelling also accepts an existing file with no extension, so the script can drop .mica, move into your PATH, and become a command in name too.

Your libraries come along

The same release introduces the project model: a mica.project beside your sources states which encoding they speak and which libraries they consume. The run mode is the third consumer of that file, after the build and the language server, and it follows the same discovery rule both already use — the nearest mica.project up the directory tree governs.

So a script written inside your project tree imports your libraries with no flags at all:

$ cat mica.project
{
    "contracts": ["build-lib"]
}
$ mica --run twice.mica       # twice.mica says: imp Twice : Numbers;
twice(21) = 42

This is the quiet answer to a loud annoyance in scripting ecosystems — import paths, virtual environments, dependency pinning for a ten-line tool. The project file your build already uses is the whole configuration, and a here-document typed inside the tree gets the same treatment.

Checked scripts

The part no scripting language offers: everything the compiler knows happens before the program runs. Type errors, format-string mismatches, unused variables, the always-on array-bounds guard — a Mica script fails at compile time where a Python script fails at runtime, in production, on the branch you didn’t test. The run mode’s default is the debug tier, so checks are at their maximum exactly where iteration happens; --optimize O2 is one flag away when a script turns out to be a workload.

The mode stays deliberately narrow: it targets the host architecture, and it combines with --optimize, --stdlib, --memory-class, and --tasking only — every other flag belongs to the build and is refused with a single line. When a script grows up, --compile --link is waiting, and the file does not change.

When

--run shipped with 6.12.5 — the same release that brings the project model. The command-line reference documents the mode, and the scripting tutorial walks the whole road against the released compiler.