Deed

A function can only do what its signature admits to.

Install

One binary: compiler, tests, formatter, WebAssembly, language server, debugger and MCP. Nothing else to install.

Download Deed 0.2.13

Pick the machine this browser is on. Each button downloads the released archive directly from GitHub.

These archives are unsigned. For automatic checksum verification and a deed command on your PATH, use the installer below. Intel Macs and Linux ARM machines can build with Rust.

Install and verify automatically

On Linux, or on an Apple-silicon Mac:

$ curl -fsSL https://raw.githubusercontent.com/deed-lang/deed/main/install.sh | sh

On Windows:

> irm https://raw.githubusercontent.com/deed-lang/deed/main/install.ps1 | iex

Either one works out which release asset fits the machine, downloads it along with the checksum list the release published, refuses it if the hash does not match, and leaves one file in your own profile: ~/.local/bin, or %LOCALAPPDATA%\Programs\deed. It never asks for a password, because it never writes anywhere that would need one, and there is nothing to uninstall but the file.

What the hash buys is worth stating exactly, since a sha256 in an install script tends to read like it proves more than it does. The checksums come from the same release as the binary, so this catches a truncated or corrupted download and does not catch a compromised release.

Piping a script into a shell is a thing worth being uneasy about. Both scripts are short and are in the repository beside the compiler — install.sh and install.ps1 — and the rest of this page is the same work done by hand.

Unpack it and ask it what it is

Pick the one for your machine and run it as written. The last line is what you should see.

Linux

$ tar xzf deed-v0.2.13-x86_64-unknown-linux-gnu.tar.gz
      $ ./deed-v0.2.13-x86_64-unknown-linux-gnu/deed --version
      deed 0.2.13

macOS

$ tar xzf deed-v0.2.13-aarch64-apple-darwin.tar.gz
      $ xattr -d com.apple.quarantine deed-v0.2.13-aarch64-apple-darwin/deed
      $ ./deed-v0.2.13-aarch64-apple-darwin/deed --version
      deed 0.2.13

The middle line is not optional and it is explained below.

Windows

> Expand-Archive deed-v0.2.13-x86_64-pc-windows-msvc.zip .
      > .\deed-v0.2.13-x86_64-pc-windows-msvc\deed.exe --version
      deed 0.2.13

What your operating system will say about it

These binaries are not code-signed. Signing needs a certificate tied to an identity, and there is not one yet, so both macOS and Windows will treat the download as something they have never seen.

macOS marks anything a browser downloaded with a quarantine attribute, and refuses to run an unsigned, unnotarised binary that carries it. Depending on the version you get “cannot be opened because the developer cannot be verified” or the process is killed with no explanation at all. Removing the attribute is the xattr line above, and it is worth understanding rather than pasting: it says you accept this file from where you got it.

Windows shows “Windows protected your PC” if you double-click the executable in Explorer. More info, then Run anyway. Starting it from a terminal, as above, is the shorter path.

Linux says nothing. The archive carries the execute bit; if you rebuilt it or copied it in a way that dropped the mode, chmod +x deed.

Where to put it

Anywhere. It reads nothing next to itself and writes nothing beside itself. The one-line install has already put it somewhere your shell looks; if you unpacked it by hand and want to type deed instead of a path, move it onto yours:

$ sudo mv deed-v0.2.13-x86_64-unknown-linux-gnu/deed /usr/local/bin/deed

On Windows, put the folder on Path through Settings, or keep using the full path. Nothing on this page needs it on Path.

A first program

deed new writes one, rather than leaving you to work the module header and the file layout out of a repository:

$ deed new greeter
greeter/greeter.deed
greeter/main.deed

next: cd greeter && deed test .

$ cd greeter
$ deed test .
./greeter.deed
  ok    a greeting carries the name it was given
  ok    there is no greeting for nobody
  ok    property greeting (100 cases)

3 passed, 0 failed

$ deed run main.deed
hello, world

Three tests out of two files, and only two of them are written down. The third is generated from the contract on greeting, which is the point: a signature is checked rather than read.

By hand instead, the whole of a program is this much:

module hello

fn main(sys: System) -> Int
  uses
    Io.write,
{
    Io.write(sys.console, "hello, world\n")
    0
}

Then:

$ deed check hello.deed
$ deed run hello.deed
hello, world

check printing nothing is the answer. It found no problem, so it has nothing to say, and it exits 0. Anything it does print is a diagnostic, and it will point at the byte it means.

The playground runs the same compiler in a browser tab, so you can try things there without any of this.

What else is in it

The same file with a different first word each time. None of them needs anything else on the machine, and deed --help is the longer version of this table.

Command What it is
deed new A project: a library module with a contract and its tests, and a program that imports it. No manifest, because a new project has no code outside its own tree.
deed check The compiler. Silence is the answer.
deed test The test blocks, and the properties a contract generates. It refuses to run anything that does not check.
deed run Calls main, handing it the one System capability there is.
deed build Compiles to WebAssembly. With --component, writes the .wit world the effect rows add up to, which is the one clause page.
deed doc A module's API reference, as Markdown. No visibility modifiers here, so there is nothing to decide about what belongs on it.
deed fmt One canonical form, and no options for the output.
deed fix Applies the repairs that are certain and leaves the guesses alone.
deed explain The page for one diagnostic code. Every code has one.
deed lsp A language server, for an editor to start rather than you.
deed debug A debug adapter: breakpoints, stepping, and the stack and bindings of every active call.
deed mcp A Model Context Protocol server, so an agent can ask the compiler the questions an editor asks.

The last one is worth a second sentence, because the argument this language is built on is that most code is no longer typed out by a person. deed mcp holds no capability: a program arrives as text and the answer leaves as text, and nothing it runs can reach a file. What it hands back is not only the diagnostics but which tier each obligation landed in, so the thing writing the code can see the difference between a contract that was proved and one that was left to a runtime check.

With Rust instead

Needs Rust 1.88 or newer, and nothing else:

$ cargo install deed-lang

deed on crates.io belongs to somebody else, so the package is deed-lang. The binary it installs is deed, and it is the same one file this page has been talking about.

From a clone, if you want the tree it was built from:

$ git clone https://github.com/deed-lang/deed
$ cd deed
$ cargo install --path crates/deed-cli

The workspace has no external dependencies, so either way this compiles the compiler and nothing from anywhere else.

When it does not work

cannot execute binary file: Exec format error
The file is for a different machine than the one running it. Check the table above against uname -m.
deed: command not found
It is not on your PATH. Run it by path, with the ./, or move it as above.
--version prints something other than 0.2.13
You are running a different deed than the one you unpacked. which deed says which.
It prints a diagnostic you do not understand
deed explain DEED5001, with the code it printed. Every code has a page.
Anything else
Open an issue with the command you ran and everything it printed. A confusing message is a bug in the message.