# The brine command

> Every brine subcommand and flag, what each one prints, its JSON output, and the exit codes it returns.

Source: https://docs.brinelang.org/tooling/cli/

Everything in Brine goes through one command, `brine`: creating projects, checking, building, running, testing, formatting and debugging. Every command that reports diagnostics takes `--json`, and exit codes are stable: `0` success, `1` your code has a problem, `2` the command line or setup has a problem, and `101` a program panicked.

```sh
brine --help
```

```text
brine — a verified, natively parallel systems language


Usage: brine <command> [options]


Project:
  new <name>            Create a new project in ./<name>
  init                  Create a project in the current directory


Build and run:
  run [file] [-- args]  Build and run (default: the current project)
      --release           optimize more
      --threads <n>       worker threads for `par` (default: all cores)
      --ranks <n>         run <n> cooperating processes (the `world` module)
      --target wasm       build WebAssembly and run it with Node.js
  build [file]          Build a native executable
      --release | --debug   optimization profile (default: dev)
      -o <path>             output path
      --emit-c              also write the generated C next to the output
      --target <t>          host (default), wasm (a .wasm module) or web (a page)
  check [file]          Type-check and verify without building (fastest)
      --report              list every runtime check the prover could not remove
  test [file] [filter]  Run `test "...":` blocks in parallel (also --target wasm)
  debug [file] [-- args]  Debug build, then launch gdb or lldb


Tools:
  fmt [files] [--check] Format source files (default: the whole project)
  explain <code>        Explain an error code, e.g. `brine explain E0601`
  guide                 Print the language quick reference
  doctor                Check that your toolchain works
  version               Print the version


Global options:
  --json                Machine-readable output (one JSON object per line)
  --color <when>        auto | always | never
  -q, --quiet           Only print errors
```

## Commands at a glance

[Section titled “Commands at a glance”](#commands-at-a-glance)

| Command                                        | What it does                                          | Flags                                                                          |
| ---------------------------------------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------ |
| [`brine new <name>`](#brine-new)               | create a project in `./<name>`                        |                                                                                |
| [`brine init`](#brine-init)                    | create a project in the current directory             |                                                                                |
| [`brine run [file] [-- args]`](#brine-run)     | build and run                                         | `--release`, `--debug`, `--threads N`, `--ranks N`, `--target wasm`, `--typed` |
| [`brine build [file]`](#brine-build)           | build an executable, a `.wasm` module or a web folder | `--release`, `--debug`, `-o PATH`, `--emit-c`, `--target T`, `--typed`         |
| [`brine check [file]`](#brine-check)           | type-check and prove, no code generation              | `--report`, `--typed`                                                          |
| [`brine test [file] [filter]`](#brine-test)    | run `test "...":` blocks in parallel                  | `--release`, `--target wasm`, `--typed`                                        |
| [`brine debug [file] [-- args]`](#brine-debug) | debug build, then gdb or lldb                         |                                                                                |
| [`brine fmt [files]`](#brine-fmt)              | format source files                                   | `--check`                                                                      |
| [`brine explain [code]`](#brine-explain)       | explain an error code, or list them all               |                                                                                |
| [`brine guide`](#brine-guide)                  | print the language quick reference                    |                                                                                |
| [`brine doctor`](#brine-doctor)                | check the toolchain                                   |                                                                                |
| [`brine version`](#brine-version)              | print the version                                     |                                                                                |

Every command also accepts the [global options](#global-options). A flag a command doesn’t know is an error, with a suggestion:

```text
error: unknown option `--reprot` (did you mean `--report`?)
```

## Which file a command works on

[Section titled “Which file a command works on”](#which-file-a-command-works-on)

`run`, `build`, `check`, `test` and `debug` take an optional file:

| You pass                                       | Brine uses                                                                                                                                                                         |
| ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| nothing                                        | the project around you: the nearest `brine.toml` in this directory or a parent, and its main file (`src/main.br` unless [`[build] main`](/tooling/projects/#build) says otherwise) |
| `file.br`                                      | that file, as a single-file program (imports load next to it)                                                                                                                      |
| a directory with `brine.toml`                  | that project                                                                                                                                                                       |
| a directory with `main.br` and no `brine.toml` | that folder’s `main.br`                                                                                                                                                            |

Outside a project and without a file, Brine says what to do:

```text
error: no brine.toml found in this directory or any parent; pass a file (`brine run hello.br`) or create a project with `brine new <name>`
```

See [Projects and brine.toml](/tooling/projects/) for where each kind of build puts its output.

## brine new

[Section titled “brine new”](#brine-new)

```sh
brine new hello
```

```text
   Created project `hello`


    cd hello
    brine run
```

Creates `hello/` with `brine.toml`, `src/main.br`, `AGENTS.md`, `README.md` and `.gitignore`, and runs `git init` unless the folder is already inside a Git repository. The name must start with an ASCII letter or `_` and contain only letters, digits, `_` and `-`. The folder must not exist yet. With `--json` it prints `{"created":"hello"}`. [Projects and brine.toml](/tooling/projects/#brine-new-and-brine-init) shows the files.

## brine init

[Section titled “brine init”](#brine-init)

```sh
mkdir myapp && cd myapp
brine init
```

```text
   Created project `myapp` (brine.toml, src/main.br, .gitignore, AGENTS.md, README.md)
```

Like `brine new`, in the current directory. The project is named after the folder (characters that aren’t allowed become `_`). Files that already exist are kept, and the message lists only the ones it wrote. It fails if the directory already has a `brine.toml`.

## brine run

[Section titled “brine run”](#brine-run)

Builds the program, then runs it. Status lines go to stderr; the program’s own output is untouched.

```sh
brine run
```

```text
     Built hello v0.1.0 [dev] in 2.05s
   Running target/dev/hello.exe
Hello, brine!
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
```

A second run with nothing changed skips the compile and the link:

```text
     Fresh hello v0.1.0 [dev] in 0.02s
   Running target/dev/hello.exe
Hello, brine!
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
```

(The first build of a project takes about two seconds because it compiles the runtime once; after that, builds take a fraction of a second.)

| Flag            | Effect                                                                                                                                                                                                                                                                                                                    |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--release`     | build with the [release profile](/tooling/builds-and-backends/#profiles) (optimized C)                                                                                                                                                                                                                                    |
| `--debug`       | build with the debug profile (no optimizations, debug info)                                                                                                                                                                                                                                                               |
| `--threads <n>` | worker threads for `par` (sets [`BRINE_THREADS`](/tooling/environment-variables/) for the program); a positive number                                                                                                                                                                                                     |
| `--ranks <n>`   | start `n` cooperating processes for the [`world` module](/parallelism/world/), 1 to 1024                                                                                                                                                                                                                                  |
| `--target wasm` | build a WebAssembly module and run it with Node.js, or with [`BRINE_WASM_RUNNER`](/tooling/environment-variables/#brine_wasm_runner); needs [wasi-sdk](/tooling/webassembly/#setup). Can’t be combined with `--ranks`. `--target web` is refused: open a web build in a browser. See [WebAssembly](/tooling/webassembly/) |
| `--typed`       | require a written type on every variable, as [`[check] typed`](/tooling/projects/#check) does                                                                                                                                                                                                                             |

### Passing arguments

[Section titled “Passing arguments”](#passing-arguments)

Everything after `--` goes to the program:

argv.br

```brine
fn main():
    print(args())
```

```sh
brine run argv.br -- one --two 3
```

```text
     Built argv [dev] in 0.10s
   Running C:/Users/you/AppData/Local/Temp/brine-cache/465ef71a47ea2199/dev/argv.exe
["one", "--two", "3"]
```

With a file, plain words after it are passed too (`brine run argv.br a b`), but anything that starts with `-` would be read as a Brine flag, so use `--`. Inside a project, always use `--`: `brine run foo` means “run the file `foo`”.

### Several processes

[Section titled “Several processes”](#several-processes)

```sh
brine run world.br --ranks 4
```

```text
     Built world [dev] in 0.10s
   Running C:/Users/you/AppData/Local/Temp/brine-cache/88f5d4ab53aec8ad/dev/world.exe (4 ranks)
4 ranks, total = 499999500000, squares = [0, 1, 4, 9]
after one lap: token->0->1->2->3
rank 3 received [[0, 3], [1, 3], [2, 3], [3, 3]]
```

Each rank is a process on this machine, connected over loopback TCP. Only rank 0’s output is shown. If one rank fails, Brine stops the others half a second later and returns the first non-zero exit code. See [Multiple processes](/parallelism/world/).

### Exit code

[Section titled “Exit code”](#exit-code)

`brine run` returns the program’s exit code: `0` when `main` returns normally, the value `main` returns if it returns an `int` (clamped to 0-255), `1` when `main` returns `Err`, and `101` after a [panic](/proofs/runtime-checks/):

panic.br

```brine
fn main():
    let xs = [1, 2, 3]
    let i = len(args())
    print(xs[i + 5])
```

```text
     Built panic [dev] in 0.09s
   Running C:/Users/you/AppData/Local/Temp/brine-cache/fce079b2338829bc/dev/panic.exe


panic: index 5 is out of bounds for an array of length 3
  --> panic.br:4:11
```

That run exits with `101`. If the program doesn’t compile, nothing runs and the exit code is `1`.

## brine build

[Section titled “brine build”](#brine-build)

Builds an executable without running it.

```sh
brine build --release
```

```text
     Built hello v0.1.0 [release] in 2.74s
    Output target/release/hello.exe
```

| Flag           | Effect                                                                                                                                                                                              |
| -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--release`    | optimized build through C at `-O3`, one translation unit                                                                                                                                            |
| `--debug`      | debug build: native code with DWARF on x86-64 Windows/Linux and AArch64 Linux, C with `-O0 -g` elsewhere ([Debugging](/tooling/debugging/))                                                         |
| `-o <path>`    | where to write the executable; on Windows `.exe` is added when the name has no extension (native builds only)                                                                                       |
| `--emit-c`     | also write the program as one C file next to the executable (`hello.exe` → `hello.c`)                                                                                                               |
| `--target <t>` | `host` (the default, also `native`), `wasm` (a WASI module, also `wasm32` or `wasi`) or `web` (a folder with `index.html`, `brine.js` and `program.wasm`). See [WebAssembly](/tooling/webassembly/) |
| `--typed`      | require a written type on every variable                                                                                                                                                            |

Where the executable goes:

| Build                | Output                                                                             |
| -------------------- | ---------------------------------------------------------------------------------- |
| project, no `-o`     | `target/<profile>/<name>` (`target/dev/hello.exe`)                                 |
| single file, no `-o` | the current directory, named after the file (`brine build tool.br` → `./tool.exe`) |
| `-o path`            | `path`                                                                             |

`--target wasm` writes `<name>.wasm` instead (`target/dev-wasm/hello.wasm` in a project), and `--target web` a folder named `<name>-web` (`target/dev-web/hello-web/`).

`--emit-c` writes the whole program as the C backend would generate it, even when the executable itself was built by the [native backend](/tooling/builds-and-backends/#backends):

```text
     Wrote target/dev/hello.c
     Fresh hello v0.1.0 [dev] in 0.02s
    Output target/dev/hello.exe
```

With `--json`, a successful build prints `{"built":"target/dev/hello.exe"}`.

## brine check

[Section titled “brine check”](#brine-check)

Parses, type-checks and runs the prover, without generating code. It is the fastest feedback loop: run it after every edit.

sum.br

```brine
fn total(xs: [int]) -> int:
    var s = 0
    for i in 0..len(xs):
        s += xs[i]
    return s


fn pick(xs: [int], k: int) -> int:
    return xs[k]


fn main():
    let xs = [1, 2, 3, 4]
    print(total(xs), pick(xs, 2))
```

```sh
brine check sum.br
```

```text
   Checked sum in 0.00s — 1 runtime check proven unnecessary, 1 remain (see --report)
```

| Flag       | Effect                                                                       |
| ---------- | ---------------------------------------------------------------------------- |
| `--report` | list every runtime check the prover couldn’t remove, one per line            |
| `--typed`  | require a written type on every variable ([E0337](/reference/errors/#e0337)) |

```sh
brine check sum.br --report
```

```text
sum.br:8:12: index bounds check `xs[k]`
   Checked sum in 0.00s — 1 runtime check proven unnecessary, 1 remain
```

`xs[i]` in `total` was proven in bounds; `xs[k]` in `pick` wasn’t, because nothing says `k` is in range. A `requires 0 <= k < len(xs)` would remove it. See [Runtime checks](/proofs/runtime-checks/).

`brine check` doesn’t need a `main` function, so it also works on library modules. It exits with `0` when there are no errors (warnings don’t count) and `1` when there are.

With `--json`:

```text
{"runtime_check":"index bounds check","location":"sum.br:8:12","code":"xs[k]"}
{"ok":true,"checks_proven":1,"checks_remaining":1}
```

## brine test

[Section titled “brine test”](#brine-test)

Builds the `test "...":` blocks of a file or project and runs each one in its own process, in parallel.

t.br

```brine
fn double(x: int) -> int:
    return x * 2


test "double doubles":
    assert double(4) == 8


test "double of zero":
    assert double(0) == 1


fn main():
    print(double(21))
```

```sh
brine test t.br
```

```text
     Built tests [dev] in 0.10s
test double doubles ... ok
test double of zero ... FAILED


---- double of zero ----


panic: assertion failed: double(0) == 1
  --> t.br:8:5


test result: FAILED. 1 passed; 1 failed; finished in 0.03s
```

| Argument or flag | Effect                                                                                                             |
| ---------------- | ------------------------------------------------------------------------------------------------------------------ |
| `file`           | a `.br` file or a directory; without one, the current project                                                      |
| `filter`         | run only the tests whose name contains this text (`brine test t.br doubles`, or `brine test doubles` in a project) |
| `--release`      | build the tests with the release profile                                                                           |
| `--target wasm`  | build the tests as a WebAssembly module and run each one with Node.js ([WebAssembly](/tooling/webassembly/#tests)) |
| `--typed`        | require a written type on every variable                                                                           |

Details:

* A test passes when it finishes without a panic. The exit code is `0` when every test passed and `1` when any failed or the tests didn’t compile.
* Each test process gets `BRINE_THREADS=2`, so many tests can run at once without each starting a thread per core, and `BRINE` set to the path of the `brine` running the tests, so a test can run the compiler.
* Results are printed in source order, whatever order the tests finish in. `--quiet` prints only the failures and the summary.
* A filter that matches nothing is not an error: it prints `(no tests match the filter; add one with `test “name”:`)` and exits with `0`.

With `--json`, one object per test:

```text
{"test":"double doubles","ok":true,"seconds":0.021,"output":""}
{"test":"double of zero","ok":false,"seconds":0.026,"output":"\npanic: assertion failed: double(0) == 1\n  --> t.br:8:5\n"}
```

## brine debug

[Section titled “brine debug”](#brine-debug)

Makes a [debug build](/tooling/debugging/), then starts gdb (or lldb, if there is no gdb) on it. Arguments after `--` go to the program. `brine debug` takes no other flags.

```sh
brine debug shapes.br
```

gdb gets Brine’s pretty-printers, so values print the way Brine prints them, and stepping skips the C runtime. Without gdb or lldb:

```text
error: no debugger found (install gdb or lldb); the debug build is at <path>
```

[Debugging](/tooling/debugging/) has a full session.

## brine fmt

[Section titled “brine fmt”](#brine-fmt)

Rewrites source files in the canonical format: 4-space indentation, one space around operators, at most one blank line, and lines up to 100 characters.

```sh
brine fmt                 # every .br file in the project
brine fmt src/main.br     # just these files (or directories)
brine fmt --check         # change nothing; exit 1 if a file would change
```

```text
would reformat messy.br
1 file checked, 1 need formatting
```

Without arguments it formats every `.br` file under the project root (or the current directory outside a project), skipping `target/` and folders whose names start with `.`. A file with a syntax error is reported and left alone. See [Formatting](/tooling/formatting/) for what it changes.

| Flag      | Effect                                                                                                                                     |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `--check` | report files that aren’t formatted (`would reformat <file>`, or `{"unformatted":"<file>"}` with `--json`) and exit with `1`; write nothing |

## brine explain

[Section titled “brine explain”](#brine-explain)

```sh
brine explain E0401
```

```text
E0401: assigning to an immutable binding


Variables declared with `let` (and loop variables) can't change. Declare the
variable with `var` if it needs to change:


    var total = 0
    total += 1
```

Without a code, it lists every code with its title. With `--json`, it prints `{"code":...,"title":...,"explanation":...}` (or one `{"code":...,"title":...}` line per code for the list). An unknown code exits with `2`. The same text is on the [error codes](/reference/errors/) page.

## brine guide

[Section titled “brine guide”](#brine-guide)

Prints the language quick reference: the whole language on one page, built into the compiler, so it works offline and always matches the installed version. It’s the same text as the [quick reference](/reference/quick-reference/) page.

```sh
brine guide | less
```

## brine doctor

[Section titled “brine doctor”](#brine-doctor)

Checks that Brine can build and run programs on this machine.

```sh
brine doctor
```

```text
  ✓ brine            0.4.0 (windows x86_64)
  ✓ C compiler       gcc — gcc (MinGW-W64 x86_64-ucrt-posix-seh, built by Brecht Sanders, r1) 16.2.0
  ✓ parallelism      32 hardware threads
  ✓ local sockets    needed for `brine run --ranks`
  ✓ build + run      compiled and ran a parallel program
  ✓ debugger         gdb
  ✓ WebAssembly      C:/Users/you/tools/wasi-sdk-34.0-x86_64-windows\bin\clang.exe
```

| Check         | What it tests                                                                                                                   |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `brine`       | the version and the platform                                                                                                    |
| C compiler    | `BRINE_CC`, `CC`, or the first of `clang`, `gcc`, `cc` that runs                                                                |
| parallelism   | how many hardware threads `par` will use by default                                                                             |
| local sockets | that a local TCP port can be reserved (for `--ranks`)                                                                           |
| build + run   | builds and runs a small `par sum` program in a temp folder and checks its output                                                |
| debugger      | gdb or lldb, for `brine debug` (optional: a missing debugger doesn’t fail)                                                      |
| WebAssembly   | wasi-sdk’s clang, through `WASI_SDK_PATH` or `/opt/wasi-sdk`, for [`--target wasm` and `web`](/tooling/webassembly/) (optional) |

It exits with `1` if a required check fails. With `--json` it prints one `{"check":...,"ok":...,"detail":...}` line per required check.

## brine version

[Section titled “brine version”](#brine-version)

```sh
brine version
```

```text
brine 0.4.0
```

`brine --version` and `brine -V` print the same; `brine version --json` prints `{"version":"0.4.0"}`. `brine help`, `brine --help` and `brine -h` print the help, as does `brine` alone.

## Global options

[Section titled “Global options”](#global-options)

These work with every command, before or after it (`brine --json check` and `brine check --json` are the same). Flags that take a value also accept `=`: `--color=never`.

| Option           | Effect                                                                                              |
| ---------------- | --------------------------------------------------------------------------------------------------- |
| `--json`         | machine-readable output on stdout, one JSON object per line; status lines are not printed           |
| `--color <when>` | `auto` (the default: color when stderr is a terminal and `NO_COLOR` isn’t set), `always` or `never` |
| `-q`, `--quiet`  | print only errors: no `Built`/`Running` lines, no warnings                                          |

### JSON output

[Section titled “JSON output”](#json-output)

In text mode, diagnostics and status lines go to stderr. With `--json`, each diagnostic is one line on stdout:

```text
{"severity":"error","code":"E0401","message":"cannot assign to `x` because it was declared with `let`","file":"bad.br","line":3,"column":5,"end_line":3,"end_column":6,"label":"immutable","related":[{"file":"bad.br","line":2,"column":9,"end_line":2,"end_column":10,"label":"declared here"}],"notes":[],"help":["declare it with `var x = ...` to make it mutable"],"fixes":[]}
```

| Field                                              | Meaning                                                                       |
| -------------------------------------------------- | ----------------------------------------------------------------------------- |
| `severity`                                         | `"error"` or `"warning"`                                                      |
| `code`                                             | the stable code (`"E0401"`), or `null` for command-line errors                |
| `message`                                          | the one-line message                                                          |
| `file`, `line`, `column`, `end_line`, `end_column` | the primary span (1-based; the end is exclusive)                              |
| `label`                                            | the text under the primary span                                               |
| `related`                                          | other spans, each with its own location and `label`                           |
| `notes`, `help`                                    | the `= note:` and `= help:` lines                                             |
| `fixes`                                            | machine-applicable edits: `{line, column, end_line, end_column, replacement}` |

Errors in the command line itself also come out as JSON when `--json` is given:

```text
{"severity":"error","code":null,"message":"unknown command `chek`; did you mean `brine check`? (see `brine help`)"}
```

Other JSON records each command prints:

| Command       | Records                                                                                                                       |
| ------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `check`       | `{"ok":true,"checks_proven":N,"checks_remaining":N}`; with `--report`, a `{"runtime_check","location","code"}` line per check |
| `build`       | `{"built":"<path>"}`                                                                                                          |
| `test`        | `{"test","ok","seconds","output"}` per test                                                                                   |
| `fmt --check` | `{"unformatted":"<path>"}` per file                                                                                           |
| `new`         | `{"created":"<name>"}`                                                                                                        |
| `explain`     | `{"code","title","explanation"}`                                                                                              |
| `doctor`      | `{"check","ok","detail"}` per check                                                                                           |
| `version`     | `{"version":"0.4.0"}`                                                                                                         |

For `run`, the program’s own output is not wrapped: it passes through as is.

## Exit codes

[Section titled “Exit codes”](#exit-codes)

| Code  | When                                                                                                                                                                                                              |
| ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `0`   | success                                                                                                                                                                                                           |
| `1`   | the program has errors (`check`, `build`, `run`, `test`, `debug`); a test failed; `fmt --check` found a file to reformat or `fmt` hit a syntax error; `doctor` found a problem; a program’s `main` returned `Err` |
| `2`   | a problem with the command itself: unknown command or option, a missing or bad value, a file that doesn’t exist, no project found, an invalid `brine.toml`, an unknown error code for `explain`                   |
| `101` | a program panicked (overflow, an out-of-bounds index, a failed `assert`, …)                                                                                                                                       |
| other | `brine run` returns the program’s own exit code (`fn main() -> int`)                                                                                                                                              |

Warnings never change the exit code.

## Internal commands

[Section titled “Internal commands”](#internal-commands)

Three more commands exist for working on the compiler itself. They aren’t in `--help` and may change in any release:

| Command                                                         | Prints                                                   |
| --------------------------------------------------------------- | -------------------------------------------------------- |
| `brine lex [--comments] <file>`                                 | the tokens                                               |
| `brine parse <file>`                                            | the syntax tree                                          |
| `brine emit-c [--tests] [--release\|--debug] <file> [-o out.c]` | the generated C (this is how the bootstrap seed is made) |

## Related

[Section titled “Related”](#related)

* [Projects and brine.toml](/tooling/projects/)
* [Builds, backends and performance](/tooling/builds-and-backends/)
* [WebAssembly](/tooling/webassembly/)
* [Environment variables](/tooling/environment-variables/)
* [Error codes](/reference/errors/)
