Tooling

Commands, projects, packages, formatting, testing, docs, and editor support.

The moon command covers the normal development loop: create a project, check it, run it, test it, format it, and build an executable. This page focuses on those day-to-day workflows.

Run moon --help to see the available commands, or moon <command> --help for a command's options.

Create and run a project

Create a new directory with a starter project:

moon new my-app
cd my-app
moon run src/main.mn

Use moon init instead when the directory already exists. A basic project has a moon.toml manifest and one or more .mn source files.

The three commands used most often are:

moon check src/main.mn
moon run src/main.mn
moon build -o my-app src/main.mn

check reports type and syntax errors without running the program. run checks and runs it. build keeps the resulting executable.

Arguments after -- go to the moon program:

moon run src/main.mn -- --port 8080

Multiple project binaries

A project with several commands or services can declare each entry point in moon.toml:

[package]
name = "moon-service"
version = "0.1.0"

[[bin]]
entrypoint = "src/server.mn"
exe_name = "moon-server"

[[bin]]
entrypoint = "src/worker.mn"
exe_name = "moon-worker"

Select a binary by name:

moon run --bin moon-server
moon check --bin moon-worker
moon build                         # build every declared binary
moon build --bin moon-server       # build one binary

For a directory of small commands, [bins] folder = "bins" discovers direct .mn children of that directory. Discovery is opt-in and does not recurse.

Testing

moon discovers zero-argument functions named test_* in *_test.mn files and under tests/ directories.

// calc_test.mn
use calc

fn test_add() {
  std.testing.assert_eq(calc.add(2, 3), 5)
}

Run all tests or narrow the run while working:

moon test
moon test calc_test.mn
moon test --filter add
moon test --list

Async test functions are supported too. Name tests that require a live service *_live_test.mn; they run only when explicitly selected or when --live is passed.

Formatting and linting

Format a file in place, check formatting without changing files, or format a directory recursively:

moon fmt --write src/main.mn
moon fmt --check .
moon fmt --write src

moon lint reports unused names, unreachable code, shadowing, naming issues, and other code-quality suggestions:

moon lint .
moon lint --fix .
moon lint --deny-warnings .

Project-wide formatting and lint choices can live in moon.toml:

[fmt]
indent = 2
line_width = 100

[lint]
enabled = true
todos = true

The formatter and editor integration read the same project settings, so saved files and command-line checks agree.

Documentation

Write /// comments immediately above public declarations:

/// Adds two numbers.
pub fn add(left: int, right: int) -> int {
  left + right
}

Then render or browse documentation with:

moon doc source src/main.mn
moon doc std strings
moon doc builtin Array

The online API reference contains the same public APIs in a browsable form.

Packages

Dependencies are recorded in moon.toml and pinned in moon.lock.

moon add https://github.com/example/greeter.git --version ^1.2
moon update
moon deps
moon vendor

Import a dependency through its package name:

use greeter.hello.greet

Commit moon.lock for applications so teammates and deployments use the same versions. moon vendor is useful when a build must work without network access.

Project tasks

If a project needs a repeatable command beyond the built-in workflow, define a named task in a root build.mn:

fn main() {
  std.build.emit([
    std.build.task(
      "check",
      [std.build.process(["moon", "check", "src/main.mn"])],
    ),
  ])
}
moon task --list
moon task check

Tasks can depend on other tasks and run programs with declared inputs. Keep the common case small; add more orchestration only when the project needs it.

Editor support

moon ships a language server. Configure an editor to start:

moon lsp

It provides diagnostics, completion, hover information, signature help, go-to-definition, references, rename, formatting, code actions, inlay hints, and project symbols. Editor integrations are available for VS Code, JetBrains IDEs, Neovim, and Zed.

Turn on format-on-save and use the project's moon.toml settings so local editing matches command-line checks.

A practical routine

For a typical change:

moon check
moon test
moon fmt --check .
moon lint .
moon build

You rarely need every command for every edit. Run the checks that match the part of the project you changed, then build the binaries you plan to ship.