adm - one language for apps, services, interfaces, and everything around them

adm

6 min read Original article ↗

ADM Bot

Programming Language

ADM is statically typed and compiles to native binaries. Contracts, transactions, services, UI components, GPU code, and interoperability with other language ecosystems are part of the system rather than separate worlds you have to stitch together.

launch.adm

module rocket {
    use std.units::*

    // Contracts belong to the function.
    def burnTime(fuel Mass, rate MassFlow) !Time {
        expects {
            assert rate > 0 onerror fail "engine off"
        }

        let t = fuel / rate
        return t

        provides {
            assert t < 10(min) onerror fail "burn too long"
        }
    }

    // A function that can run on the GPU.
    cuda def cool(temps float64[], by float64) !none {
        int i = blockIdx.x * blockDim.x + threadIdx.x;
        if (i < temps_len) temps[i] -= by;
    }

    // Foreign runtimes are callable too.
    @external.node("telemetry.js")
    async def publish(message string);
}

application Launch {
    use (std.units::* rocket)

    let fuel Mass = 0

    def load(m Mass) {
        begin { fuel += m }
        rollback { fuel -= m }
    }

    def fuelUp(m Mass) !none {
        transaction {
            load(m)
            let t = try rocket.burnTime(fuel, 2.5(t/s))
            println("burn for {t.str(s)}")
        } onerror (err error) {
            println("scrubbed: {err.message}")
            recover none
        }
        return none
    }

    def new(args string[]) int {
        fuelUp(2000(t)) onerror return 1

        let temps = float64[910.0, 870.0, 1020.0, 880.0]

        // One iteration per CPU worker.
        forall let (i, temp) in temps {
            rocket.publish("engine {i}: {int(temp)} K")
        }

        // SIMD is a language-level type.
        let v vec4<float64>
        if v.load(temps, 0).gt(v.splat(1000.0)).any() {
            rocket.cool(temps, 50.0) onerror recover none
        }

        return 0
    }
}

Built into the language

ADM is not trying to win by adding one more spelling for classes and loops. The interesting parts are the things that usually live in frameworks, build systems, runtimes, or entirely different toolchains.

Polyglot by design

Use the code you already have.

Interop in ADM is not just a C FFI. Bind functions from native libraries, or call code running in JavaScript/Node, Python, Lua, Ruby, PHP, R and other embedded runtimes. Bridging layers reach JVM languages such as Java and Kotlin, .NET languages such as C#, and more. A foreign function still looks like a typed ADM function at the call site.

Read about external functions and FFI →

JavaScript Java / JVM .NET / C# Python Lua / LuaJIT Ruby C / C++ Rust / Go WASM + more

Contracts & transactions

Functions can declare what they expect and provide. A function can also define its own begin and rollback behavior, then participate in a larger transaction without a transaction framework around it.

Services are a language concept

Long-running stateful systems get a shared model: queries, commits, events, observers and lifecycle. Logging, storage, schedulers, messaging, UI and your own services speak the same language-level vocabulary.

Dependencies do not get everything

ADM traces a package's path to files, the network, devices and other privileged services. The developer chooses what dependencies may reach; runtime policy lets the user narrow that access further. adm audit shows why a permission is needed.

From a loop to the GPU

Use ordinary loops, spread work across cores with forall, operate on native SIMD vector types, or compile a cuda def for the GPU. Parallelism is not hidden behind a collection of unrelated libraries.

Units that calculate

Numbers can carry units: 100(km), 9.81(m/s²). Arithmetic derives the resulting dimension, and a value can be displayed in any compatible unit. Hundreds of units and prefixed forms are built in.

Native apps without the web stack

Build the interface in the same language as everything else and ship one native binary. No browser engine, no bundler, no second toolchain. Dozens of ready-made components get a real window on screen fast, and your edits show up while the app is still running.

A few very ADM things

Small ideas matter too. These are the details that make everyday ADM code feel like ADM.

datatype UserLike

Describe shape separately from behavior

Interfaces describe methods. Datatypes describe the properties a value has. Both are satisfied structurally.

value.tags()

Metadata can travel with a value

Tags follow a value through assignments, calls, collections and channels instead of disappearing at the next boundary.

component Login

UI stays in the language

View, style and controller use ADM syntax, ADM control flow and ADM types rather than a separate template language.

application / library / plugin

The compiler knows what you are building

Applications, libraries, plugins and modules are compilation units, not conventions invented by an external build tool.

Scale the code, not the ceremony

Start with ordinary typed code. Reach for more of the language only when the problem actually needs it.

def Write the function Typed values, generics, errors, pattern matching and ordinary control flow.

async · channel · forall Add concurrency Coordinate tasks or spread work across cores without changing ecosystems.

vec<T> · cuda def Push the hot path Use native SIMD or move the work to the GPU when the data says it is worth it.

@external.* Reuse another ecosystem Call existing code instead of rewriting it merely because it was written in another language.

Download

ADM ships as a single package: the compiler and the standard library, with a bundled C toolchain on Linux and Windows and the Xcode Command Line Tools' clang on macOS.

Install with one command (current user, no sudo):

curl -fsSL https://raw.githubusercontent.com/admlang/adm/main/install.sh | sh

Installs into ~/.adm and adds ~/.adm/bin to your PATH. Later, adm update fetches new releases. Prefer to do it by hand? Grab the adm-<version>-linux-amd64.tar.gz from the latest release, unpack it anywhere and put its bin/ on PATH.

Editor plugins

Both plugins run the adm you installed, so the editor reports what the compiler itself computes: diagnostics as you type, completion, navigation, rename, formatting and your check suites. .

IntelliJ IDEA JetBrains IDEs 2025.2 and later. Install with Settings, Plugins, Install Plugin from Disk. Adds run and debug and the ADM tool window. Visual Studio Code Version 1.88 and later. Search for ADM in the Extensions view, or install it from the Marketplace page. Adds tests in the Testing view, commands and tasks.

AI coding tools get the same answers through the compiler's MCP server: adm mcp install all registers it with Claude Code, Codex, Cursor, Gemini CLI, VS Code, Zed and the others it finds. See adm mcp install.