Skip to content

The geas CLI

The compiler is one binary, geas. It carries the whole pipeline, lexer through type checker through codegen, and every command below runs on that pipeline.

usage: geas <command> [file]
commands:
version print the compiler version
lex <file> dump the token stream of a source file
parse <file> dump the AST of a source file
check <file> load the program rooted at file and check it
build <file> emit the module C and link it into a shared library
build --bin <file> link a standalone executable around the Main contract
emit-header <file> write the C header naming the module's hashes and symbols
emit-proto <file> write the gRPC .proto and the Go and TypeScript session wrappers

Prints the compiler version and exits.

Terminal window
geas version

lex dumps the token stream of a source file, one line per token, with any faults on stderr. The dump prints even when the file faults, so a broken file still shows what was scanned. parse dumps the AST.

Terminal window
geas lex skeleton/hello.geas
geas parse skeleton/hello.geas

Both are inspection commands: useful when a parse surprises you or when you want to see exactly what the compiler sees.

Loads the program rooted at the named file, resolves its imports, and runs the full static check without emitting anything.

Terminal window
geas check skeleton/hello.geas

This is the fast loop for development: every type error, every visibility violation, and the requirements policy proof run here.

build reads the source, emits the module C, and links it with cc into a loadable .geas.so:

Terminal window
geas build skeleton/hello.geas

The compiled module carries descriptor tables that spell every contract, every pledge and its signature, and every vow and its default. When the runtime loads the module it registers all of it in the iname table, and a foreign host drives a contract through a handful of C calls with no binding generated for it.

build --bin links a standalone executable around the Main contract:

Terminal window
geas build --bin skeleton/main_demo.geas

A program declares exactly one Main contract with a run(args: List<String>) -> Result<Int, E> pledge. The generated wrapper signs Main, hands argv to run as a List<String>, and maps the result onto the process exit code: Ok(n) becomes the exit code, and an Err renders itself to stderr and exits 1. A --bin module still emits every contract in the file, not Main alone.

emit-header writes the C header a foreign host compiles against:

Terminal window
geas emit-header skeleton/hello.geas

The header names the module’s shape hashes and every mangled pledge name as C defines, so a host resolves and signs against generated names instead of hardcoded strings. A version or shape mismatch then fails at compile or discovery time with a descriptive error. See Interop.

emit-proto writes the contract’s gRPC surface:

Terminal window
geas emit-proto skeleton/payment.geas

It emits the .proto, where every pledge is its own typed rpc and signing is a stream whose lifetime is the instance’s, plus the session wrappers protoc cannot write: a Go session wrapper for a Go module and a TypeScript session wrapper for a Node host over @grpc/proto-loader. No protoc step and no native code. A consumer in any gRPC language builds against the .proto with stock tooling.

Two variables control where the toolchain finds things:

  • GEAS_ROOT points cc at the runtime headers and libgeasrt. Set it to a checkout of the repository and geas build works from any directory; without it, run geas from the repository root so the relative include path resolves.
  • GEAS_HOME points the loader at the standard library. An import resolves beside the root file first and then under GEAS_HOME. See Source files and packages.
Terminal window
export GEAS_ROOT=~/src/geas
export GEAS_HOME=~/src/geas/lib

From a checkout of the repository, two make targets are the front door:

Terminal window
# build everything and run the end to end check
make smoke
# the same check under the address and leak sanitizers
make smoke-asan

make smoke builds four things in order: the runtime shared library libgeasrt.so, the geas binary through the dusk toolchain, a compiled contract module from the skeleton, and the C host. Then it runs the host, which loads the module, signs a contract, fulfills a pledge, checks the result, exercises the error paths, and breaks the contract. Everything lands under target/.

For the full walk from a fresh clone, see Getting started.