Installing Osprey

By Christian Findlay · Last verified 25 July 2026

Osprey compiles your program to textual LLVM IR and then hands that IR to clang to produce and link a native executable. The osprey binary does not bundle LLVM — it shells out to a clang already on your system. So installing Osprey is two steps:

  1. Install the LLVM/clang toolchain (the prerequisite).
  2. Install the osprey compiler.

This is required. The release tarballs and the Homebrew/Scoop packages ship only the osprey binary and its C runtime archives — never LLVM itself. If clang is not on your PATH, compiling any program fails with an error like clang: command not found or failed to spawn C compiler. Install the toolchain first.

What Osprey needs

Task Required tools
Compile & run native programs clang (a full LLVM clang, 15 or newer)
Link the C runtime on Windows clang plus MinGW gcc
Compile to WebAssembly (--target=wasm32) clang, wasm-ld (from lld), a WASI sysroot
Debug info (--debug, DWARF line tables) LLVM 19 or newer recommended

Any recent LLVM release works for everyday compilation — there is no exact version to match. When in doubt, install your platform's current LLVM.

macOS

The quickest path uses Apple's bundled clang from the Xcode Command Line Tools, which is enough to compile and run native Osprey programs:

xcode-select --install

For a current, full LLVM (recommended for WebAssembly, debug info, or if you hit an IR-compatibility error with Apple's older clang), install it with Homebrew:

brew install llvm

Homebrew's llvm is keg-only — its clang is deliberately kept off your PATH so it does not shadow Apple's. Point Osprey at it in one of two ways:

# Option A — put Homebrew LLVM ahead of Apple's clang for this shell:
export PATH="$(brew --prefix llvm)/bin:$PATH"

# Option B — leave PATH alone; tell Osprey which compiler to use per-invocation:
OSPREY_CC="$(brew --prefix llvm)/bin/clang" osprey app.osp --run

Then install the compiler:

brew install nimblesite/tap/osprey

Linux

Install clang, llvm, and (for WebAssembly) lld from your distribution:

# Debian / Ubuntu
sudo apt-get update && sudo apt-get install -y clang llvm lld

# Fedora / RHEL
sudo dnf install -y clang llvm lld

# Arch
sudo pacman -S --needed clang llvm lld

Osprey is distributed for Linux via the Homebrew tap (or the release tarball):

brew install nimblesite/tap/osprey

Windows

Osprey shells out to clang and links the C runtime with MinGW's gcc, so you need both LLVM and MinGW. Scoop installs them as dependencies of the osprey package:

scoop bucket add nimblesite https://github.com/Nimblesite/scoop-bucket
scoop install osprey

If you install Osprey another way (e.g. the release tarball), install the toolchain yourself:

scoop install llvm gcc

Alternatively, install the official LLVM release and a MinGW-w64 toolchain, and make sure both clang.exe and gcc.exe are on your PATH.

Verify the toolchain

After installing, confirm clang resolves and is a full LLVM clang:

clang --version

Then compile and run a program:

echo 'fn main() = print("Osprey is installed")' > hello.osp
osprey hello.osp --run

You should see Osprey is installed.

Debugging in VS Code

Install the Osprey extension and LLDB, including its lldb-dap executable. Open an .osp or .ospml file, set a breakpoint and press F5. The extension builds a native debug executable and launches LLDB-DAP. If the adapter is outside your PATH, set osprey.debug.lldbDapPath to its full path in VS Code settings.

Breakpoints inside a lambda can inspect its primitive parameters, captures and local bindings, including at the return line of a block containing just one expression. Functions stored in records retain their source names and inspectable arguments. Shared mutable cells show their current values as handlers update them. Effect handler arms expose their parameters and captures, including when they resume a continuation. Extracted GPU kernels running on the host support the same breakpoints and show their captured values. Within a match arm or nested block, the debugger shows its primitive bindings and initialized local values; leaving that scope restores enclosing names. This also works inside closures and effect handlers. A local appears after its initializer finishes. While initializing a shadowing binding, you can still inspect the enclosing value; later declarations stay hidden. This also applies to shared mutable cells. Expand a record to inspect its named fields and nested values. This covers anonymous records, concrete generic records and records replaced in shared cells by handlers. Collections, unions, Results and closures still need dedicated displays; optimized-away value reporting remains unfinished. See the debugger contract for the supported build and source-mapping behavior.

To build a debug executable from the command line:

osprey hello.osp --debug --debug-opt=none --compile --debug-out hello-debug --debug-preserve-ir

This keeps the executable and its generated IR (hello-debug.ll) for inspection. Add "preserveArtifacts": true to a VS Code launch configuration to keep the IR from an editor build, or set "compilerPath" to select a compiler for that launch. Editor launches always build without optimization. Optimized debugging and heap inspection are still planned; unsupported CLI modes report an error.

For programs that read input, add "console": "integratedTerminal" to the launch configuration. "externalTerminal" uses VS Code’s configured external terminal. Both terminal modes require LLDB-DAP 21 or newer; an older or unrecognised adapter produces a clear error. The default "internalConsole" displays output in the Debug Console and does not provide stdin.

The OSPREY_CC override

When several clangs coexist — for example a keg-only Homebrew LLVM, or the MinGW clang on Windows that must match the MinGW-built runtime archive — set OSPREY_CC to the exact driver Osprey should invoke instead of the default clang:

OSPREY_CC=/opt/homebrew/opt/llvm/bin/clang osprey app.osp --run

Troubleshooting

  • clang: command not found / failed to spawn C compiler — LLVM is not installed, or its clang is not on your PATH. Install it (above) or point OSPREY_CC at a working clang.
  • Homebrew says osprey is installed but compiling fails — Homebrew's llvm is keg-only. Add $(brew --prefix llvm)/bin to your PATH, use OSPREY_CC, or install the Xcode Command Line Tools for Apple's clang.
  • An IR / bitcode version error when compiling — your clang is older than the IR Osprey emits. Install a current LLVM and select it with PATH or OSPREY_CC.
  • WebAssembly build can't find wasm-ld — install lld (brew install lld on macOS, your distro's lld package on Linux). See the Web Apps guide for the full Wasm toolchain.

No install required

To try Osprey without any toolchain, use the browser-based Playground — it compiles and runs Osprey entirely in your browser, no LLVM needed.