Terrane is an experimental programming language for writing high-level native software without making low-level representation machinery part of everyday programming.
The project aims to offer one approachable language across ordinary applications, libraries, services, command-line tools, WebAssembly, embedded systems, firmware, and kernels. Terrane is intended to feel lightweight when a program is simple while allowing types, ownership, visibility, platform capabilities, and other constraints to be stated where they matter.
Terrane is built around a simple distinction: what a value means in the language is not the same thing as how it must be represented at runtime.
Everything is an object semantically. An integer is an object, a function is an object, a type is an object. But object semantics do not require object-shaped runtime machinery. If an integer can be realised directly as a machine value, Terrane may lower it to one. If a call can be resolved statically, it may become a direct Rust call. If value semantics can be preserved without a physical copy, the compiler is free to avoid one.
The programmer describes semantics; the compiler chooses representation. The aim is to keep the conveniences normally associated with high-level languages while compiling away machinery that does not need to survive into the final program, with the generated Rust left in place as the receipt.
Modern software often asks developers to cross several language, build-system, and runtime boundaries as a project grows. Terrane explores a different approach: keep the human-facing language coherent, lower onto the mature Rust and native-code ecosystem rather than a bespoke runtime black box, and make the boundary between convenient source and deployed software visible rather than magical.
Its guiding priorities are:
- Semantic objects, efficient representation. Everything is an object at the language level, but the compiler is free to realise values as native scalars, direct calls, enums, borrowed values, or other efficient representations when doing so preserves observable behaviours.
- Readable everyday code. Common syntax should favour clear words and familiar control flow over punctuation-heavy ceremony.
- Progressive strictness. Start with concise bindings and add precise contracts at the function, type, package, or build level when needed.
- Native reach. The same language should be able to target applications, libraries, WebAssembly, embedded devices, and systems software when the program uses capabilities available in that environment.
- Ecosystem access. Rust crates, native libraries, and platform APIs should be usable without turning Terrane into an island.
- Inspectable lowering. Generated Rust is not hidden compiler exhaust: it is the public lowered form, available for auditing, debugging, profiling, and understanding why the compiler made a particular representation, allocation, copy, or performance choice.
- Explicit power. Shared identity, ownership transfer, unsafe operations, and platform-specific facilities should be visible choices rather than hidden surprises.
Designing a new source language does not require designing a new execution platform.
Mature dynamic languages require substantial runtimes because much of their language machinery remains active between source code and execution: object representation, dispatch, memory management, interpreters or virtual machines, extension interfaces, platform integration, and often a JIT. Rebuilding all of that would consume enormous effort while producing machinery that already exists elsewhere.
Terrane takes a different approach. The project concentrates on the part it actually intends to change - the human-facing language and its semantics - and lowers those semantics to Rust. Rust already provides a mature native compilation ecosystem, optimisation, ownership machinery, platform support, linking, C interoperability, WebAssembly, no_std, debugging, and access to a large systems ecosystem.
This also means Terrane does not need every high-level abstraction to survive as runtime machinery. An object may become a scalar, a dynamic call may become a direct call, an independent value assignment may require no copy, and an exact numeric conversion may become a machine operation. What matters is preserving Terrane semantics, not preserving their most general implementation.
Rust is therefore not hidden underneath Terrane as an implementation accident. It is the deliberate lower layer: Terrane is where the program is expressed; Rust is where its concrete native realisation can be inspected or taken over when necessary.
Terrane is a source language designed to behave like a semantic layer over Rust rather than a separate execution world. The boundary between the two is deliberate and useful. Terrane semantics do not always map one-for-one onto Rust, which gives the compiler room to enforce stronger source guarantees, translate runtime failures into Terrane-level errors, select efficient representations, and remove machinery that is no longer observable.
Rust also provides a much safer foundation for the execution layer itself. Building a bespoke runtime means taking responsibility for memory management, object lifetime, dispatch, concurrency, native-extension boundaries, buffer handling, platform integration, and a large amount of security-sensitive infrastructure. Rust cannot eliminate every class of bug, especially across unsafe and foreign interfaces, but it removes a substantial amount of memory-safety risk from the default implementation model.
The alternative is therefore not merely the engineering cost of building a large managed-language runtime. It is also the long-term security, compatibility, optimisation, and maintenance burden of owning an execution platform. Terrane instead spends its complexity on language semantics and lowering, while inheriting a mature native toolchain and a safer implementation substrate.
Terrane compiles at development and build boundaries, not at execution boundaries. Its lowering is deterministic and incrementally cacheable, and the generated Rust participates in the existing Cargo/rustc caching ecosystem. Large native programs still take time to build because large native programs take time to build; that cost is paid when the program changes, not every time it runs.
Terrane is still in design, but the compiler has progressed well beyond the prototype-parser stage. The language document describes the proposed full contract; the implemented subset is intentionally smaller.
The working terrane CLI can check, lower, build, and run manifest-backed programs through deterministic generated Rust and Cargo. One shared pipeline now covers the lexer and lossless parser, packages and namespaces, typed semantics, explicit Rust IR, Cargo build caching, structured Terrane errors, and compiler-owned member families. The implemented language surface includes native scalars, exact adaptive integers, fixed-width arithmetic policies and named results, typed bindings and calls, control flow, descriptors, strings and grapheme iteration, immutable bytes, explicit Unicode text views and encodings, the version-one string transformation and search families, and linear async tasks on a selected wake-driven runtime. Native task scopes interleave child futures on that runtime, projected dependency futures execute in its context, and compiler-owned asynchronous stream, TCP, UDP, DNS, and TLS operations delegate unavoidable blocking host calls without occupying executor workers. A manifest-driven conformance corpus exercises accepted, rejected, generated-Rust, and runtime contracts; later collections, general iterator protocols, deeper ownership coverage, and broader platform capabilities remain planned rather than implemented.
Terrane-generated crates pin the exact stable Rust release the compiler supports, currently 1.93.1,
and rustup installs that pin when it is first needed. terrane --version reports both the stable
build toolchain and the pinned rustdoc nightly. A package can explicitly set
rust-toolchain = "system" to use its ambient compiler instead. terrane toolchains reports only
pins Terrane has previously requested; it never removes toolchains or recommends removal.
Compiler-owned Cargo invocations use sccache only when
TERRANE_SCCACHE=1 explicitly opts in. An unavailable cache is not an error, and repository checks
and benchmarks never clear it.
Projects that declare [rust-dependencies] additionally require Linux
bubblewrap (bwrap) on PATH. Local projection
fallback uses the pinned nightly toolchain; dependencies satisfied by a prepared projection
artifact do not. Bubblewrap contains Cargo and rustdoc inspection of third-party packages;
dependency-free Terrane projects do not require it.
Set TERRANE_PROJECTION_ARTIFACT_URL to a trusted HTTPS projection repository to try exact
precomputed dependency surfaces before local rustdoc. Terrane verifies dependency, feature, target,
toolchain, rustdoc-format, projection-schema, and SHA-256 payload identity. Content-origin
resolution events and fallback reasons are persisted in terrane-projection.lock; cache hits do
not rewrite that provenance. A verified artifact is cached locally for subsequent offline builds.
Bundled artifacts are deliberately deferred until Terrane has a
release artifact channel, and resolution records that source as skipped.
The CLI integration suite regenerates a reviewed representative dependency stack and compares its
machine-independent projection lock byte for byte. Upstream additions, removals, signature or
identity changes, and newly declined members therefore require an explicit reviewed lock update.
Cargo retains downloaded registry indexes and crate archives in CARGO_HOME, so repeated toolchain and conformance builds do not download unchanged dependencies again. The conformance runner additionally reuses one generated Cargo workspace for all accepted cases in a corpus run. With explicit opt-in, sccache provides further reuse across separate runs and branches.
Generated Rust is returned exactly as Terrane lowering emits it. Compiler work can pass
--require-canonical-rust after any CLI command name to compare that untouched output with the
compiler-bundled formatter. A mismatch fails as compiler defect S9004; the formatter never
silently rewrites the generated artefact.
terrane rust <source> writes one complete standalone Rust translation unit to stdout. For a
cleaner inspectable file, terrane rust --output lowered.rs <source> (or -o lowered.rs) writes the
authored application lowering to lowered.rs and compiler-owned prelude, runtime, error and source
site infrastructure, selectively bundled /core implementation code, and projected /deps
lowering to the sibling lowered.support.rs. The sidecar is emitted even when empty so
named lowering always has one uniform two-file shape. The entrypoint imports that sidecar with
one relative include!; check, build, and run explicitly request src/main.rs as the
generated Cargo entrypoint through the same path-parameterized renderer.
terrane build --release and terrane run --release compile generated programs with Cargo's
optimized release profile. Development and release executables are cached separately.
The language specification and compiler architecture draft is the main source for syntax, semantics, examples, interoperability, tooling, and other technical details.
The first-version compiler plan describes the implementation milestones and the capabilities targeted for the first usable release.
The scientific mathematics benchmark corpus compares clean Terrane, standard-library Python, Rust, and Go implementations under shared correctness, runtime, and peak-memory contracts. Its checked-in reports preserve the full machine, toolchain, build, and process evidence behind published measurements.
The demos/ directory contains exploratory design exercises. These files deliberately stress ambitious or unfinished ideas and should not be read as examples of features already supported by a compiler.
Editor support lives under editors/. The VS Code extension launches the Rust terrane-language-server, which reuses the recovering compiler frontend for semantic highlighting and source diagnostics.
