Getting started
Geas compiles contracts into shared libraries that any language can drive across the C ABI. This page builds the toolchain, compiles a contract, and runs it end to end.
What you need
Section titled “What you need”- The dusk toolchain, version 1.5.3 or newer. The Geas compiler is written in dusk.
- A C compiler. Both
ccandclangare used. make.
Build everything
Section titled “Build everything”Clone the repository and run the smoke check:
git clone https://github.com/choice404/geascd geasmake smokemake smoke builds the runtime library libgeasrt.so, builds the geas compiler, compiles the skeleton contract, builds a C host, and runs the whole loop: the host signs the contract, fulfills a pledge, checks the result, exercises the error paths, and breaks the instance. If it prints a passing result, everything works.
To run the same check under the address and leak sanitizers:
make smoke-asanYour first contract
Section titled “Your first contract”The skeleton contract lives at skeleton/hello.geas:
GreetError is either Empty
contract Greeter { vow prefix: String = "hello, "
pledge greet(name: String) -> Result<String, GreetError> { return Ok(prefix + name) }
// Abstract: no body here, the host binds an implementation before sign. pledge shout(name: String) -> Result<String, GreetError>}Three things to notice.
The vow is an immutable field. It has a default here, and a host can override it at sign time. Once the contract is signed, nothing can change it.
The first pledge has a body, so the contract fulfills it itself. The second has no body. It is abstract, and a host in another language must bind an implementation before the contract will sign.
Every pledge returns Result or Option. Errors are values in Geas, and nothing throws across a language boundary.
Compile it
Section titled “Compile it”target/dusk-out/geas build skeleton/hello.geasThis emits C, compiles it, and links target/geas-out/libhello.geas.so, a loadable module that carries descriptor tables spelling out every contract, pledge, and vow inside it.
Drive it from a host
Section titled “Drive it from a host”The runtime enforces the terms at the boundary. A host does five things: initialize the runtime, load the module, sign the contract, fulfill pledges, and break the instance. In C that looks like this:
GeasRuntime* rt = NULL;geas_runtime_init(NULL, &rt);geas_module_load(rt, "target/geas-out/libhello.geas.so");
GeasContract* c = NULL;geas_contract_sign(rt, "Greeter", NULL, 0, 0, &c);
GeasValue out;GeasValue name = str_arg("world");geas_pledge_fulfill_sync(c, "greet", &name, 1, NULL, 0, &out);// out is Ok("hello, world")
geas_contract_break(c);The same module can be driven from Python with the ctypes wrapper, with no C written and no bindings generated. See Python hosts for that side of the story.
Standalone programs
Section titled “Standalone programs”Geas also works on its own. A program is a contract named Main with a run pledge:
DemoError is either BadMood(reason: String) or Empty
contract Main { vow greeting: String = "counted"
pledge run(args: List<String>) -> Result<Int, DemoError> { let mut n = 0 for a in args { if a == "fail" { return Err(BadMood("asked to fail")) } n = n + 1 } return Ok(n) }}Build and run it:
target/dusk-out/geas build --bin skeleton/main_demo.geasOk(n) becomes the exit code. An Err prints to stderr and exits with 1.
Where to next
Section titled “Where to next”- The language tour covers the rest of the language.
- Contracts and the lifecycle explains what signing really does.
- Interop shows the full boundary story.