# AGENTS.md and common mistakes

> The AGENTS.md file Brine writes into every new project, and each rule in it that trips people up, with the wrong code, the compiler's error and the fix.

Source: https://docs.brinelang.org/agents/agents-md/

Every project made by `brine new` or `brine init` has an `AGENTS.md` that tells coding agents how to work in it: the commands to run, and the rules that most often trip up a model, or a person, who knows Python. This page shows the file, then takes each rule in turn with code that breaks it, what the compiler says, and the fix.

## The file

[Section titled “The file”](#the-file)

This is the `AGENTS.md` that `brine new hello` writes (Brine 0.4.0):

AGENTS.md

```md
# AGENTS.md — working on `hello`


This is a brine project. brine is a compiled,
verified, natively parallel language with Python-like syntax.


## Commands
- `brine check` — type-check and verify (fast; run after every edit)
- `brine run` — build and run `src/main.br`
- `brine test` — run all `test "...":` blocks
- `brine fmt` — format all sources (always run before committing)
- `brine guide` — the full language reference (read it once)
- `brine explain <CODE>` — explanation of any error code, e.g. `brine explain E0601`


Add `--json` to any command for machine-readable output (one JSON object per line).


## Rules that commonly trip people up
- `let` is immutable, `var` is mutable; no shadowing.
- No implicit numeric conversions: write `float(i)`, `int(x)`.
- Arguments are passed by value. A function that changes the caller's variable
  declares `ref x: T` and callers write `f(ref x)`; methods use `ref self`.
- `requires`/`ensures`/`invariant`/`prove` must be proven at compile time.
  If the prover can't, the error lists the known facts; add an `invariant`,
  a `requires`, or an `assert` (runtime check that becomes a known fact).
- Inside `par for i in ...:` you may only write `out[i]` of outer arrays.
- Maps: `m[k]` panics if `k` is missing; test with `k in m` or use `m.get(k)`.
- No negative indexes (`xs[-1]` is an error); write `xs[len(xs) - 1]`.
- Strings index and slice by bytes; `s[i]` is a one-character `str`.
- One expression can't change a variable and also read it, or change it twice
  (`print(xs.pop(), xs)`, `xs.push(xs.pop())`); split it into two statements.
  Uses on different sides of `and`/`or`/`if-else` are fine.
- Types are optional (`let x = 5` or `let x: int = 5`); if brine.toml has
  `typed = true` under `[check]`, every `let`/`var`/`for` variable needs one.
- `match` must cover every case; read enum variant data with `match`, not `.field`.
- Expected failures return `Result[T, E]` (`Ok(x)` / `Err(e)`) or `Option[T]`
  (`Some(x)` / `None`); `panic` is for bugs. `x?` passes a failure up to the caller.
```

The file is yours to edit: add your project’s own conventions below the generated part. `brine init` doesn’t overwrite an existing `AGENTS.md`.

## let is immutable, var is mutable

[Section titled “let is immutable, var is mutable”](#let-is-immutable-var-is-mutable)

`let` declares a name that never changes; `var` declares one that can. Each name is declared once per function, so there’s no shadowing either.

```brine
fn main():
    let count = 0
    for i in 0..3:
        count += i
    print(count)
```

```text
error[E0401]: cannot assign to `count` because it was declared with `let`
 --> letlet.br:4:9
  |
4 |         count += i
  |         ^^^^^ immutable
2 |     let count = 0
  |         ----- declared here
  |
  = help: declare it with `var count = ...` to make it mutable
  = run `brine explain E0401` for more about this error
error: could not compile due to 1 error
```

Fix: declare it with `var`.

```brine
fn main():
    var count = 0
    for i in 0..3:
        count += i
    print(count)
```

Declaring the same name again is [E0207](/reference/errors/#e0207); pick a new name, or make the first one a `var` and assign to it. See [Bindings](/language/bindings/).

## No implicit numeric conversions

[Section titled “No implicit numeric conversions”](#no-implicit-numeric-conversions)

`int` and `float` (and `i32`, `u8`, …) never convert on their own, not even in arithmetic or comparisons.

```brine
fn mean(xs: [float]) -> float:
    return sum(x for x in xs) / len(xs)


fn main():
    print(mean([1.0, 2.0, 3.0]))
```

```text
error[E0305]: cannot divide `float` and `int`
 --> conv.br:2:12
  |
2 |     return sum(x for x in xs) / len(xs)
  |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `/` with mismatched operands
  |
  = help: brine never converts numbers implicitly; use `float(x)` or `int(x)`
  = run `brine explain E0305` for more about this error
error: could not compile due to 1 error
```

Fix: convert explicitly. `int(x)` truncates toward zero, and conversions to smaller types such as `i32(n)` are checked.

```brine
fn mean(xs: [float]) -> float:
    return sum(x for x in xs) / float(len(xs))


fn main():
    print(mean([1.0, 2.0, 3.0]))
```

See [Values and types](/language/values-and-types/).

## Arguments are passed by value; ref changes the caller’s variable

[Section titled “Arguments are passed by value; ref changes the caller’s variable”](#arguments-are-passed-by-value-ref-changes-the-callers-variable)

Arguments are copies, and parameters are read-only. A function that changes the caller’s variable declares a `ref` parameter, and the caller writes `ref` too, so the change is visible where it happens.

```brine
fn add_one(ref xs: [int]):
    xs.push(1)


fn main():
    var xs: [int] = []
    add_one(xs)
    print(xs)
```

```text
error[E0402]: parameter `xs` is a `ref`; pass the argument with `ref`
 --> refex.br:6:13
  |
6 |     add_one(xs)
  |             ^^ the callee may modify this
  |
  = help: passing by reference is always visible at the call site in brine
  = run `brine explain E0402` for more about this error
error: could not compile due to 1 error
```

Fix: `add_one(ref xs)`.

```brine
fn add_one(ref xs: [int]):
    xs.push(1)


fn main():
    var xs: [int] = []
    add_one(ref xs)
    print(xs)
```

Methods work the same way. A method that changes its struct takes `ref self`; with plain `self`, the receiver is read-only:

```brine
struct Counter:
    n: int


    fn bump(self):
        self.n += 1


fn main():
    var c = Counter(n=0)
    c.bump()
    print(c.n)
```

```text
error[E0403]: cannot assign to parameter `self`
 --> refself.br:5:9
  |
5 |         self.n += 1
  |         ^^^^^^ parameters are read-only
4 |     fn bump(self):
  |             ---- declared here
  |
  = help: to change a local copy, declare it `mut self: ...`; to change the caller's variable, declare it `ref self: ...` and call with `ref`
  = run `brine explain E0403` for more about this error
error: could not compile due to 1 error
```

Fix: `fn bump(ref self):`. The call stays `c.bump()`.

```brine
struct Counter:
    n: int


    fn bump(ref self):
        self.n += 1


fn main():
    var c = Counter(n=0)
    c.bump()
    print(c.n)
```

To change a local copy without touching the caller’s value, declare the parameter `mut x: T`. See [Functions](/language/functions/).

## Contracts must be proven at compile time

[Section titled “Contracts must be proven at compile time”](#contracts-must-be-proven-at-compile-time)

`requires`, `ensures`, `invariant` and `prove` are not runtime checks. The compiler must prove them, or the program doesn’t compile. Here `first_or_last` calls `last` without knowing that `xs` is non-empty:

```brine
fn last(xs: [int]) -> int:
    requires len(xs) >= 1
    return xs[len(xs) - 1]


fn first_or_last(xs: [int]) -> int:
    return last(xs)


fn main():
    print(first_or_last([1, 2, 3]))
```

```text
error[E0601]: cannot prove the precondition of `last`
 --> lastreq.br:6:12
  |
6 |     return last(xs)
  |            ^^^^^^^^ this call might violate `requires len(xs) >= 1`
2 |     requires len(xs) >= 1
  |              ------------ precondition declared here
  |
  = note: nothing is known here about the values involved
  = note: to prove: len(xs) > 0
  = help: add an `assert` before the call to check it at runtime, or a `requires` to this function so its callers must prove it
  = run `brine explain E0601` for more about this error
error: could not compile due to 1 error
```

The notes list what the prover knew (“nothing”) and what it needed. There are three fixes. Pass the obligation to the callers with a `requires`:

```brine
fn last(xs: [int]) -> int:
    requires len(xs) >= 1
    return xs[len(xs) - 1]


fn first_or_last(xs: [int]) -> int:
    requires len(xs) >= 1
    return last(xs)


fn main():
    print(first_or_last([1, 2, 3]))
```

Or check it at runtime with an `assert`, which the prover then knows is true:

```brine
fn last(xs: [int]) -> int:
    requires len(xs) >= 1
    return xs[len(xs) - 1]


fn first_or_last(xs: [int]) -> int:
    assert len(xs) >= 1
    return last(xs)


fn main():
    print(first_or_last([1, 2, 3]))
```

Or handle the case where it’s false:

```brine
fn last(xs: [int]) -> int:
    requires len(xs) >= 1
    return xs[len(xs) - 1]


fn last_or(xs: [int], default: int) -> int:
    if len(xs) == 0:
        return default
    return last(xs)


fn main():
    print(last_or([1, 2, 3], 0), last_or([], 0))
```

For loops, the missing fact is usually an `invariant`. Don’t weaken or delete the contract to make the error go away. See [Contracts](/proofs/contracts/) and [Fixing proof failures](/proofs/fixing-proof-failures/).

## par for may only write out\[i]

[Section titled “par for may only write out\[i\]”](#par-for-may-only-write-outi)

Inside a `par` body, variables from outside are read-only. The one exception: `par for i in ...` may write element `i` of an outer array, exactly the loop variable. Any other write could race with another iteration.

```brine
fn main():
    let n = 8
    var out = [0] * n
    par for i in 0..n - 1:
        out[i + 1] = i
    print(out)
```

```text
error[E0501]: cannot assign to `out` inside a `par` body
 --> parwrite.br:5:9
  |
5 |         out[i + 1] = i
  |         ^^^^^^^^^^ would be a data race
  |
  = note: `out` is shared by all parallel iterations
  = help: a `par for` may only write `out[i]` (its own element); to combine values use `par sum(...)`, `par [...]`, or a sequential loop
  = run `brine explain E0501` for more about this error
error: could not compile due to 1 error
```

Fix: index the write with the loop variable and shift the read instead, or build the array with `par [...]`. To add values up, use a reduction such as `par sum(...)`.

```brine
fn main():
    let n = 8
    var out = [0] * n
    par for i in 1..n:
        out[i] = i - 1
    let same = par [0 if i == 0 else i - 1 for i in 0..n]
    print(out, out == same)
```

See [Race freedom](/parallelism/race-freedom/).

## m\[k] panics if k is missing

[Section titled “m\[k\] panics if k is missing”](#mk-panics-if-k-is-missing)

Reading a missing key stops the program. This compiles, then panics when it runs:

```brine
fn main():
    var counts = {"a": 1}
    for w in ["a", "b", "a"]:
        counts[w] += 1
    print(counts)
```

Output

```text
panic: key "b" is not in the map
  --> mapmiss.br:4:9
```

Fix: test with `in`, or read with `get`, which returns an `Option` (or a default when you pass one).

```brine
fn main():
    var counts: {str: int} = {}
    for w in ["a", "b", "a"]:
        if w in counts:
            counts[w] += 1
        else:
            counts[w] = 1
    print(counts, counts.get("z", 0))
```

Output

```text
{"a": 2, "b": 1} 0
```

See [Maps](/language/maps/).

## No negative indexes

[Section titled “No negative indexes”](#no-negative-indexes)

`xs[-1]` isn’t the last element. It’s out of bounds, and the program stops when it gets there:

```brine
fn main():
    let xs = [10, 20, 30]
    print(xs[-1])
```

Output

```text
panic: index -1 is out of bounds for an array of length 3
  --> lastneg.br:3:11
```

This is a runtime panic, not a compile error, so `brine check` won’t flag it. Fix: count from the end with `len`.

```brine
fn main():
    let xs = [10, 20, 30]
    print(xs[len(xs) - 1], xs[len(xs) - 2:])
```

See [Arrays](/language/arrays/).

## Strings index and slice by bytes

[Section titled “Strings index and slice by bytes”](#strings-index-and-slice-by-bytes)

`len(s)`, `s[i]` and `s[a:b]` count bytes of UTF-8. For ASCII text that’s the same as characters; for other text it isn’t:

```brine
fn main():
    let s = "héllo"
    print(len(s), len(s.chars()), s[0], s[1:3])
    let at = s.find("l").unwrap()
    print(at, s[at:])
```

Output

```text
6 5 h é
3 llo
```

`é` is two bytes, so the first `l` is at byte 3. Use positions from `find` rather than counting characters, and walk characters with `for c in s` or `s.chars()`. See [Strings](/language/strings/).

## One expression can’t change a variable and read it

[Section titled “One expression can’t change a variable and read it”](#one-expression-cant-change-a-variable-and-read-it)

An expression that changes a variable (a mutating method such as `pop`, or a `ref` argument) can’t also read it or change it again elsewhere. Then the order in which arguments are evaluated can never change the result.

```brine
fn main():
    var xs = [1, 2, 3]
    xs.push(xs.pop())
    print(xs)
```

```text
error[E0405]: `xs` is changed twice in the same expression
 --> pushpop.br:3:13
  |
3 |     xs.push(xs.pop())
  |             ^^^^^^^^ changed here
  |     ----------------- and changed here
  |
  = help: make one change in its own statement first, e.g. `let v = ...`, then use `v`
  = run `brine explain E0405` for more about this error
error: could not compile due to 1 error
```

Fix: split it into two statements.

```brine
fn main():
    var xs = [1, 2, 3]
    let v = xs.pop()
    xs.push(v)
    print(xs)
```

`print(xs.pop(), xs)` is the same error (“changed and also read”). Uses on different sides of `and`, `or` or `if`/`else` are fine, because only one side runs first.

## Types are optional, unless the project says otherwise

[Section titled “Types are optional, unless the project says otherwise”](#types-are-optional-unless-the-project-says-otherwise)

`let x = 5` and `let x: int = 5` are both fine. A project can require a written type on every variable with this in `brine.toml`:

brine.toml

```toml
[check]
typed = true
```

`brine check --typed` does the same for one run. This program compiles normally:

```brine
fn main():
    let x = 5
    var total: int = 0
    for i in 0..x:
        total += i
    print(total)
```

With `--typed`, each variable without a type is an error, with the type to add:

```sh
brine check --typed typed.br
```

```text
error[E0337]: `x` has no written type
 --> typed.br:2:9
  |
2 |     let x = 5
  |         ^ add `: int`
  |
  = note: this project asks for a type on every variable (`typed = true` in brine.toml, or `--typed`)
  = run `brine explain E0337` for more about this error
error[E0337]: `i` has no written type
 --> typed.br:4:9
  |
4 |     for i in 0..x:
  |         ^ add `: int`
  |
  = note: this project asks for a type on every variable (`typed = true` in brine.toml, or `--typed`)
  = run `brine explain E0337` for more about this error
error: could not compile due to 2 errors
```

Fix: `let x: int = 5` and `for i: int in 0..x:`. In `--json` output, each E0337 carries a fix that inserts the type. See [Projects](/tooling/projects/).

## match must cover every case

[Section titled “match must cover every case”](#match-must-cover-every-case)

A `match` has to handle every possible value. The error names a value it misses:

```brine
enum Color:
    Red
    Green
    Blue


fn name(c: Color) -> str:
    match c:
        case Color.Red:
            return "red"
        case Color.Green:
            return "green"


fn main():
    print(name(Color.Blue))
```

```text
error[E0320]: this `match` doesn't handle every possible value
 --> nomatch.br:7:11
  |
7 |     match c:
  |           ^ of type `Color`
  |
  = note: not handled: `Color.Blue`
  = help: add `case Color.Blue:`, or a catch-all `case _:`
  = run `brine explain E0320` for more about this error
error: could not compile due to 1 error
```

Fix: add the case, or end with `case _:`.

## Read enum data with match, not .field

[Section titled “Read enum data with match, not .field”](#read-enum-data-with-match-not-field)

The fields of an enum variant aren’t readable with `.`, because the value might be a different variant:

```brine
enum Shape:
    Circle(radius: float)
    Square(side: float)


fn main():
    let s = Shape.Circle(radius=1.0)
    print(s.radius)
```

```text
error[E0205]: enum `Shape` has no fields
 --> field.br:7:13
  |
7 |     print(s.radius)
  |             ^^^^^^ use `match` to read the data in a variant
  = run `brine explain E0205` for more about this error
error: could not compile due to 1 error
```

Fix: match on the variant and bind its fields.

```brine
enum Shape:
    Circle(radius: float)
    Square(side: float)


fn main():
    let s = Shape.Circle(radius=1.0)
    match s:
        case Shape.Circle(r):
            print(r)
        case Shape.Square(side):
            print(side)
```

See [Enums and match](/language/enums-and-match/).

## Failures are Result and Option, not exceptions

[Section titled “Failures are Result and Option, not exceptions”](#failures-are-result-and-option-not-exceptions)

Brine has no exceptions. An expected failure is a `Result[T, E]` or an `Option[T]`; `panic` is for bugs. `x?` returns a failure to the caller, so the function using it must return a matching `Result` or `Option`:

```brine
fn parse_bit(s: str) -> Result[int, str]:
    if s == "0":
        return Ok(0)
    if s == "1":
        return Ok(1)
    return Err(f"not a bit: {s}")


fn main():
    let b = parse_bit("1")?
    print(b)
```

```text
error[E0341]: `?` needs the function to return Result[..., str]
 --> qmark.br:9:13
  |
9 |     let b = parse_bit("1")?
  |             ^^^^^^^^^^^^^^^ this returns from a function that returns `()`
  |
  = help: change the return type to `Result[..., str]`, or handle the value with `match`
  = run `brine explain E0341` for more about this error
error: could not compile due to 1 error
```

Fix: handle it with `match`, or make the function return a `Result`. `main` may return `Result[(), E]`; an `Err` prints `error: ...` and exits with status 1.

```brine
fn parse_bit(s: str) -> Result[int, str]:
    if s == "0":
        return Ok(0)
    if s == "1":
        return Ok(1)
    return Err(f"not a bit: {s}")


fn main() -> Result[(), str]:
    let b = parse_bit("1")?
    print(b)
    match parse_bit("7"):
        case Ok(v):
            print(v)
        case Err(e):
            print("bad input:", e)
    return Ok(())
```

See [Error handling](/language/error-handling/).

## Related

[Section titled “Related”](#related)

* [Using Brine with coding agents](/agents/overview/)
* [Coming from Python](/getting-started/from-python/): more differences, with their errors
* [Error codes](/reference/errors/)
