brine new creates a project with a program, a test, and an AGENTS.md for
coding agents. From then on the loop is: edit, brine check, brine run,
brine test. This page walks through each command with the output it prints.
You need Brine installed first.
Create and run a project
Section titled “Create and run a project”-
Create the project:
Terminal window brine new hello -
Go into it and run it:
Terminal window cd hellobrine runBuilt hello v0.1.0 [dev] in 2.04sRunning target/dev/hello.exeHello, brine![0, 1, 4, 9, 16, 25, 36, 49, 64, 81]The first build also compiles Brine’s runtime, so it takes a couple of seconds. Later builds reuse it. (On Linux and macOS the binary is
target/dev/hello, with no.exe.) -
Run it again without changing anything:
Terminal window brine runFresh hello v0.1.0 [dev] in 0.02sRunning target/dev/hello.exeHello, brine![0, 1, 4, 9, 16, 25, 36, 49, 64, 81]Freshmeans nothing changed, so Brine ran the binary it already had.
The Built, Fresh and Running status lines go to stderr; your program’s
output goes to stdout. Add -q to hide the status lines.
What’s in a project
Section titled “What’s in a project”hello/├── .gitignore├── AGENTS.md├── README.md├── brine.toml└── src/ └── main.brbrine new also runs git init in the folder, unless it’s already inside a
git repository. To turn an existing folder into a project, run brine init
in it; it creates the same files and skips any that already exist.
brine.toml
Section titled “brine.toml”[package]name = "hello"version = "0.1.0"The file marks the project root. brine commands look for it in the current
folder and its parents, so you can run them from anywhere inside the project.
The program starts at src/main.br. See Projects for the
other settings, such as [check] typed = true.
src/main.br
Section titled “src/main.br”# Welcome to brine! Run this program with `brine run`.
fn greet(name: str) -> str: return f"Hello, {name}!"
fn main(): print(greet("brine"))
# parallel by default: this runs across all your cores let squares = par [i * i for i in 0..10] print(squares)
test "greeting": assert greet("you") == "Hello, you!"fn main() is where the program starts. par [...] builds the list of squares
on every core. The test block at the end is a test, which brine run ignores
and brine test runs.
AGENTS.md
Section titled “AGENTS.md”Instructions for coding agents working in the project: the commands to run and
the rules that most often trip up someone who knows Python. Many coding agents
read AGENTS.md on their own when they start work in a folder. See
AGENTS.md and common mistakes for its full text and an
explanation of each rule.
.gitignore and README.md
Section titled “.gitignore and README.md”.gitignore holds one line, /target: builds and the build cache go in
target/ (target/dev/, target/release/, target/cache/). README.md is a
short stub for you to fill in.
Check, run, test, format
Section titled “Check, run, test, format”| Command | What it does |
|---|---|
brine check |
type-check and prove, without building; the fastest feedback |
brine run |
build src/main.br and run it |
brine test |
build and run every test "...": block, in parallel |
brine fmt |
rewrite every source file in the standard format |
brine build |
build a binary into target/dev/ (or target/release/ with --release) |
brine check
Section titled “brine check”brine check Checked hello in 0.00s — 0 runtime checks proven unnecessary, 1 remain (see --report)check parses, type-checks, and runs the prover. It doesn’t build anything, so
it’s the command to run after every edit. The second half of the line counts
the safety checks (array bounds, overflow, division by zero) that the prover
removed and those that stay in the program as runtime checks. --report lists
the ones that remain:
brine check --reportsrc/main.br:10:24: overflow check `i * i` Checked hello in 0.00s — 0 runtime checks proven unnecessary, 1 remainThe prover handles linear arithmetic, so it can’t show that i * i stays in
range; the program checks it at runtime instead. A remaining check is not an
error. See Runtime checks.
brine test
Section titled “brine test”brine test Built tests [dev] in 0.10stest greeting ... ok
test result: ok. 1 passed; 0 failed; finished in 0.02sEach test runs in its own process. brine test shout runs only the tests whose
names contain shout. See Testing.
brine fmt
Section titled “brine fmt”brine fmt1 file checked, 0 reformattedThere’s one standard format (4-space indentation, spaces around operators), so
code always looks the same. brine fmt --check changes nothing and exits with
status 1 if a file needs formatting, for CI. See Formatting.
The edit-run loop
Section titled “The edit-run loop”Here is one round of changes: add a function and a test, make a mistake, and fix it.
-
Add a
shoutfunction and a test for it tosrc/main.br. Write it carelessly, and pass it a number by mistake:src/main.br # Welcome to brine! Run this program with `brine run`.fn greet(name: str) -> str:return f"Hello, {name}!"fn shout(name:str)->str:return greet(name).upper()fn main():print(greet("brine"))print(shout(42))# parallel by default: this runs across all your coreslet squares = par [i * i for i in 0..10]print(squares)test "greeting":assert greet("you") == "Hello, you!"test "shouting":assert shout("you") == "HELLO, YOU" -
Check it:
Terminal window brine checkerror[E0301]: mismatched types--> src/main.br:11:17|11 | print(shout(42))| ^^ expected `str`, found `int`|= help: convert with `str(...)` or use an f-string like f"{x}"= run `brine explain E0301` for more about this errorerror: could not compile due to 1 errorEvery error has a code, the exact place, and a hint.
brine explain E0301explains the code at length. Change the call toshout("brine"). -
Format the file:
Terminal window brine fmtFormatted src/main.br1 file checked, 1 reformattedfn shout(name:str)->str:is nowfn shout(name: str) -> str:, and its body is indented by 4 spaces. -
Run the tests:
Terminal window brine testBuilt tests [dev] in 0.09stest greeting ... oktest shouting ... FAILED---- shouting ----panic: assertion failed: shout("you") == "HELLO, YOU"--> src/main.br:21:5test result: FAILED. 1 passed; 1 failed; finished in 0.03sThe expected string is missing its
!. Fix the test to compare with"HELLO, YOU!"and runbrine testagain:Built tests [dev] in 0.09stest greeting ... oktest shouting ... oktest result: ok. 2 passed; 0 failed; finished in 0.02s -
Run the program:
Terminal window brine runBuilt hello v0.1.0 [dev] in 0.09sRunning target/dev/hello.exeHello, brine!HELLO, BRINE![0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Single files and release builds
Section titled “Single files and release builds”You don’t need a project to try something. Every command also takes a file:
brine run scratch.brbrine check scratch.brbrine test scratch.brbrine run scratch.br -- first second # arguments after `--` go to the programbrine run --release and brine build --release optimize through the C
compiler. They take longer to build and run faster:
brine build --release Built hello v0.1.0 [release] in 2.59s Output target/release/hello.exe- A tour of Brine: the rest of the language in one page.
- Coming from Python: what’s the same and what isn’t.
- The brine command: every command and flag.