Skip to content

Repository files navigation








term

A reactive modeling language Ψ




Introduction

Term is a programming framework built on a simple, indentation-based syntax (the tree format). You write the logic once, and one source compiles to idiomatic Rust, TypeScript, Kotlin, and Swift, so the same program runs in the browser, on Node, on native servers, and on iOS and Android. It is dependently typed with a rich type system, ships with a full toolchain (compiler, package manager, and language server), and is designed so the compiler can reach near-optimal native code on each target without the author giving up a clean, readable surface.

Every platform has its own language, its own build tools, its own ecosystem. Writing an app that runs on servers, browsers, iOS, and Android means learning four toolchains, maintaining four codebases, and watching them drift apart. The logic is the same. The plumbing is not.

Dart, through Flutter, has a comparable multi-platform reach but different goals: Term emits each platform's native idioms rather than shipping one runtime, and puts a formal type system and proof checker at the center. Kind is the closer relative on that side, a dependently typed language with a small core, while Term aims more squarely at building real cross-platform applications.

You write the usual types, classes, functions, and data models. Beyond that, templates can parse the tree AST directly, so the boilerplate of building a structure of any shape is generated rather than written by hand.

The kernel underneath is a small dependent type theory: quantitative type theory (each value tracks how many times it is used), observational equality, a cumulative universe hierarchy, and self types. On top of it, a .tree file can state a theorem and prove it by structural induction, rewriting, and a fixed set of proof steps, and the kernel checks the proof. The same checker verifies ordinary code, discharging assertions through decision procedures for linear arithmetic, ring identities, congruence closure, and nonlinear non-negativity.

Most types are inferred, and a language server gives live diagnostics, hovers, completion, and go-to-definition, with a parser that recovers from errors instead of stopping at the first one. Compilation is incremental, rebuilding only the modules that changed, and the package manager follows the pnpm model, with a content-addressed store and linked dependencies.

Doing this optimally is the hard part. Because meaning is fixed by the type system rather than by how the code is phrased, the backend is free to specialize, monomorphize, and lower aggressively per target, so speed comes from the compiler rather than from the author writing awkward code.

On the application side, the standard library is written in .tree and covers the usual primitives, collections, IO, text, time, and cryptography, each mapped to its native counterpart. The web stack is reactive in the fine-grained style, updating the DOM directly through signals rather than diffing a virtual DOM, with server-side rendering, client takeover, and hot module reload.

Toward Optimal Programs

The goal with Term is to iterate and refine code toward maximal performance while keeping it clearly readable on the other end. These have always been treated as a trade-off: you write it the way you want to read it, or you contort it into the shape the machine wants. Term is built on the premise that they are two representations of one meaning, and that the translation between them is the compiler's job, not the author's.

With AI in the loop, that translation becomes an almost automated process. You write the program as you want to read it. An agent then iterates on the lowering: profiling the emitted Rust, TypeScript, Kotlin, or Swift, trying alternative specializations, measuring, and keeping what wins. Because the type system fixes the meaning precisely, every rewrite can be checked against the source for equivalence, so the loop can run unattended without drifting from what you wrote. The proof kernel makes this stronger than testing: a transformation is not just plausible, it is verified.

Compilers already do this within a fixed budget of built-in passes. The difference is that the search no longer has to stop where the pass list ends. Optimization becomes an open-ended refinement process that accumulates: each program converges toward the best known lowering for its targets, and improvements found for one program feed back into the shared patterns used by all of them. The readable source stays the single artifact you maintain. Everything below it is regenerated, re-verified, and only ever gets faster.

The end state is that the performance ceiling of a Term program is the performance ceiling of the hardware, not of the author's willingness to write unreadable code. You describe the program once, clearly, and the toolchain carries it the rest of the way to essentially optimal machine behavior on every platform it touches.

The book

A complete, example-first guide lives in book/. It is a tree of short cheatsheet pages: each one opens with a reference of every keyword, command, or operator in its topic, then shows the .tree you write to use it, with a note on how it maps to ideas you already know.

Start with the syntax model, then read what you need: the language (functions, forms, matching, loops, traits, templates, modules, and more), proofs, the standard library, the web framework, command-line apps, and the term toolchain.

Packages

This repository is a monorepo. Each part of the ecosystem is a deck (a package) under deck/. A deck's name comes from the deck <name> line in its own deck.tree, not from package.json, and the decks import each other by that name (@term/base/code/list), linked locally through term link.

The compiler, CLI, language server and package manager are written in TypeScript (under each deck's code/). The standard library, the app framework and everything else are written in .tree and compiled by the compiler itself.

Finding your way around

.
├── deck/                 every package
│   ├── make/             @term/make   the compiler (TypeScript)
│   │   └── code/
│   │       ├── parser/   .tree text to a generic tree, and diagnostic codes
│   │       ├── compile/  mill to typed AST, then one emitter per backend
│   │       │             (typescript.ts, rust.ts, kotlin.ts, swift.ts, wgsl.ts)
│   │       ├── check/    type inference, the kernel, the prover, contracts
│   │       ├── lint/     lint rules
│   │       └── format/   the formatter
│   ├── mill/             @term/mill   the DSL grammars, one mine.tree and
│   │   └── code/<name>/  mint.tree per dialect (code, view, host, zone, ...)
│   ├── call/             @term/call   the CLI, built to host/line.js
│   │   └── code/         line.ts is the entry, make.ts the build driver,
│   │                     test.ts the test runner, hold.ts the proof gate
│   ├── flow/             @term/flow   the language server
│   ├── deck/             @term/deck   the package manager
│   ├── base/             @term/base   the standard library, all .tree
│   │   ├── code/         one file per type (list.tree, text.tree, ...)
│   │   │   ├── mask/     traits
│   │   │   ├── proof/    equality and proof lemmas
│   │   │   └── native/   per-platform impls (node, browser, rust, swift, kotlin, shared)
│   │   ├── test/         stdlib tests
│   │   └── hold.json     the proof baseline `term hold` reads
│   ├── site/             @term/site   app framework: DOM, http, graphics
│   ├── face/             @term/face   headless UI components
│   ├── bind/             @term/bind   typed platform bindings, the largest deck
│   ├── host/             @term/host   the data dialect, read at run time
│   ├── feed/             @term/feed   text and binary format grammars
│   ├── cask/             @term/cask   native app shell: window, WebView, bridge
│   ├── scan/             @term/scan   dependency and advisory scanning
│   └── test/             @term/test   fuzzing, benchmarks, model checking
├── book/                 the language guide, one cheatsheet page per topic
├── test/                 the TypeScript suites, by area (parser/, check/,
│                         compile/, call/, native/, ...)
├── host/line.js          the built CLI. Rebuild it after editing any .ts
├── link/                 locally linked decks
└── deck.tree             this workspace's own declaration

Where to start digging:

you want open
what a keyword means book/, then the dialect in deck/mill/code/
why a file fails to compile deck/make/code/check/
what a backend emits deck/make/code/compile/<target>.ts
what a CLI command does deck/call/code/line.ts, then the file it dispatches to
a stdlib type or task deck/base/code/<name>.tree
the tests for any of it test/<area>/

Design notes, plans and the roadmap live outside this tree, in the parent repository's note/term/.

How It Works

.tree source
    ↓
make (compiler): parse → resolve → check → emit
    ├─→ TypeScript  (browsers, Node.js)
    ├─→ Rust        (servers, CLI, embedded)
    ├─→ Kotlin      (Android, JVM)
    ├─→ Swift       (iOS, macOS)
    ├─→ LLVM        (native binaries)
    └─→ WGSL        (GPU shaders)

The compiler parses .tree files into a surface AST, mills them into a typed AST, resolves names, and type-checks through a gradual, bidirectional inference pass that elaborates into a dependent kernel for soundness. Each backend then emits idiomatic output for its platform. Generics, traits, async, and effects lower to the natural construct on each target: native traits on Rust, protocols on Swift, interfaces on Kotlin, and monomorphization on LLVM and WGSL.

The CLI (call) drives the whole pipeline and ships a dev server with hot module reload. The language server (flow) reuses the same analysis for diagnostics, hover, and go-to-definition.

Installation

pnpm add @cluesurf/term -g

Developing Term

Working on Term itself takes Node, pnpm, Rust, Swift, a JDK, Kotlin, Maven and, for the mobile suites, the Android SDK and the iOS simulator. One command checks them all on macOS, Linux or Windows, and installs what is missing with --commit:

sh task/dev/bootstrap/start.sh check
sh task/dev/bootstrap/start.sh install --commit
powershell -ExecutionPolicy Bypass -File task\dev\bootstrap\start.ps1 check

Getting Started

# Compile a project
term make

# Run in dev mode (watch + hot reload)
term flow

# Add a package
term deck save <package>

# Run tests
term test

Example

task double
  take value, like number
  like number
  send back
    call add
      read value
      read value

Compiles to:

Rust

fn double(value: i64) -> i64 {
    return value + value;
}

TypeScript

export function double(value: number): number {
  return value + value
}

License

MIT

ClueSurf

Made by ClueSurf, meditating on the universe.

About

A reactive modeling language Ψ

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

8 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages