Source files and packages
A Geas source file is a list of top level declarations: contracts, records, sums, provisional clauses, and imports. A file is a module, and a directory of files is a package.
Source files are UTF-8 and end in .geas. Statements and declarations are terminated by a newline; there are no semicolons. A string literal that is not valid UTF-8 is a compile error, not a silent replacement.
Imports
Section titled “Imports”An import names a module by a dotted path:
import std.mathimport std.collectionsA dotted path resolves beside the root file first and then under GEAS_HOME. A directory is a package and a file is a module within it.
Every imported file parses into one shared tree, with each file’s spans mapped back to its own source, so a diagnostic names the right place even when the fault is in an imported module.
Two conditions on the import graph are named errors rather than silent behavior:
- A cycle in the import graph is an error. The compiler reports it instead of looping or picking an arbitrary order.
- A duplicate import is an error. Importing the same module twice from one file is refused, not deduplicated quietly.
What a module shares
Section titled “What a module shares”A module lends another its record and sum shapes, its error sums, its provisional clauses, and its contracts themselves. A pledge in one module can sign a contract declared in another, fulfill its pledges, and break it. That is how the standard library works: import std.math brings the MathOps contract into scope, and any pledge body can sign it. See Standard library.
Visibility
Section titled “Visibility”Visibility is by package, and it is always stated by the shape of the code, never inferred.
Exported by default. A declaration is exported from its package by default and visible to any importer. There is no pub keyword to remember; the default is open.
internal confines to the directory. A declaration marked internal is invisible outside its own directory:
internal contract Helper { pledge assist(x: Int) -> Result<Int, CommonError>}An internal contract or provisional clause cannot be incorporated, signed, or named in a type annotation from another package. An internal contract never reaches the descriptor tables or the iname table a foreign host discovers, so internal is a real boundary at the ABI, not a style hint.
The boundary holds at every position, including nested ones. An internal type cannot leak through a public signature. If an exported pledge returns Result<Secret, E> and Secret is internal to another package, that is an error, and the same rule applies at any nesting depth: a list of an internal record, an internal sum in the error slot, an internal type inside a tuple. The compiler checks every position where a type can appear.
internal applies to contracts and provisional clauses:
ContractDecl ::= [ "internal" ] "contract" IDENT [ Attrs ] "{" NL { Member NL } "}"ProvClause ::= [ "internal" ] "provisional" "clause" IDENT "{" NL { ClauseSig NL } "}"Deterministic builds
Section titled “Deterministic builds”Two builds of one source emit byte identical module C. This is a checked property, not an aspiration: the repository carries a determinism gate that builds twice and compares the output.
Determinism matters here because the module C is the interop artifact. The descriptor tables, the mangled names, and the shape hashes a foreign host resolves against all come out of that emission, so a build that varied from run to run would make the discovery story unreliable. Instead, the same source always produces the same module, the same hashes, and the same names.
Layout summary
Section titled “Layout summary”| Concept | Meaning |
|---|---|
| File | A module, one .geas file |
| Directory | A package, the unit of visibility |
import a.b | Bring module b from package a into scope |
| Resolution | Beside the root file first, then under GEAS_HOME |
| Default visibility | Exported to any importer |
internal | Confined to the declaring directory, held at every type position |
| Import cycle | Named error |
| Duplicate import | Named error |
| Build output | Byte identical C for identical source |
Related pages
Section titled “Related pages”- The geas CLI covers
GEAS_HOMEandGEAS_ROOT. - Type system covers the types a module declares and shares.
- Grammar has the full production rules for imports and declarations.