loom
Luce Engineering LuciaOS

Running programs

loom has two run paths. A compiled .lc needs only the runner. A .luc source may need the separate luce compiler to produce or refresh a cached library first.

FormWork performed
loom run FILE.lc [ARGS]Validate the artifact, load it, and call it.
loom FILE.lc [ARGS]Shorthand for run.
loom luce FILE.luc [ARGS]Resolve the full source project, reuse or build its library artifact, then run it.
loom FILE.luc [ARGS]Shorthand for the source form.

Arguments after the program path belong to the program. They arrive in main(args: list(string)); a program that needs none may declare func main():.

A .lc is a native library artifact

The compiler creates this form explicitly:

Shell
$ luce build app.luc --emit=library
$ loom run app.lc one two

--emit=library matters: the default luce build output is a standalone executable named after the source. The library form is for loom or another compatible host.

Running a current .lc performs no compilation and needs neither LLVM nor the luce binary. The artifact contains native code linked to Luce's runtime and exports the one entry loom calls.

The tag is checked before loading

Every artifact records its tag layout, target machine, host ABI version, code-generator identity, and source/program hash. loom reads and validates that metadata before asking the platform loader to map the file.

A missing file, a non-Luce library, truncated metadata, a different target, an old host ABI, a different code generator, and a stale source hash are different failures and are reported as such. There is no interpreter fallback: an artifact that cannot be trusted is not run.

Source runs use a content-checked cache

loom luce FILE.luc resolves imports and packages, creates the verified serialized hand-off, and checks for a matching native library. The cache key covers every loaded source and the project/package resolution inputs, not only the entry file's timestamp.

Where the artifact lives depends on the source:

  • A standalone source with no governing luce.yaml uses FILE.lc beside the source.
  • A governed project mirrors the entry's path under PROJECT/.luce/cache/. Deleting that cache is safe; the next run rebuilds it.
  • A source that has no writable named location uses a private directory under the user's temporary directory, addressed by its content hash.

A warm run invokes no external compiler. A cold run locates luce, asks it to turn the verified .lcm hand-off into a library, validates the result, and atomically places it in the cache. Temporary hand-off and partial output files are removed on success and failure. Concurrent writers use distinct temporary names, so a cache entry is never a half-written library.

How loom finds the compiler

loom first looks beside its own executable, then on the PATH it was given. This makes the checked installer self-contained even when an editor or GUI process starts with a minimal system path. The compiler in turn reads LUCE_LIB and LUCE_CC for runtime-library and linker policy.

If no current cache entry exists and no compiler can be found, loom names both places it looked. A direct .lc run does not perform this search because it has nothing to compile.

What the invoking shell receives

The program's status passes through. The defined result classes are:

StatusMeaning
0The program returned normally.
1The program trapped, or loom itself could not load/compile the requested program.
3A recoverable Luce error reached the entry uncaught.
70The runtime ran out of memory.
71The host could not run the program or deliver its output.
another valueThe program called exit(status).

Debug artifacts carry source locations and function names for traps. Release artifacts keep function names but omit source locations; safety and status semantics do not change.