# Agent setup (/docs/agents) marmot works the same for a coding agent as for a person, with output an agent can act on without opening files. ## Register the MCP server [#register-the-mcp-server] `marmot mcp` serves `build`, `run`, `test`, `check`, `fix` and `explain` over the Model Context Protocol on stdin and stdout. Each tool takes a directory and returns marmot's JSON output. ```sh claude mcp add marmot -- marmot mcp ``` Other agents take the same command: `marmot mcp`, with no arguments. ## As a plain command [#as-a-plain-command] When one of these variables is set (to anything but `0`) and `MARMOT_OUTPUT` is not, marmot writes its diagnostics as JSON Lines: `CLAUDECODE`, `AI_AGENT`, `CODEX_SANDBOX`, `GEMINI_CLI`, `CURSOR_AGENT`, `OPENCODE`, `GOOSE_TERMINAL`. `MARMOT_OUTPUT=json` asks for it anywhere. Each diagnostic carries its spans, the enclosing function, the source lines around it, the fixes as edits with how safe each is, and `rendered`, the exact text a person would see. See [JSON output](/docs/diagnostics/json) for the schema and [Error codes](/docs/diagnostics/codes) for every code. ## These docs, for agents [#these-docs-for-agents] Every page has a Markdown twin, linked as View as Markdown under its title. The whole site is also available as plain text: - [`/llms.txt`](/llms.txt): an index of every page. - [`/llms-full.txt`](/llms-full.txt): every page in one file. # Benchmarks (/docs/benchmarks) All numbers compare marmot with `go build` (Go 1.27) on the same machine. A program counts only if its output is identical to Go's. Each result is the median of five runs after one warm-up run. These are early numbers from a young compiler. They will change. ## Run time [#run-time] Apple M3 Pro, 43 programs. | Build | Average speed against Go | | --- | --- | | `marmot build` (dev, fast code generator) | not measured yet | | `marmot build` (dev, `MARMOT_TIER0=0`) | 1.4x faster | | `marmot build -release` | 1.6x faster | "Average" is the geometric mean. 33 of the 43 programs are faster than Go in release mode and 10 are slower. An 8-core Intel desktop running Linux gives a similar picture: 1.6x faster on average over 45 programs. ### By kind of program [#by-kind-of-program] | Program | What it stresses | Against Go | | --- | --- | --- | | convolution | numeric loops | 17.8x faster | | bit tricks | integer operations | 10.1x faster | | sum, min, max | simple loops over slices | 8.9x faster | | struct copy | copying values | 4.6x faster | | interface calls | method calls through interfaces | 3.5x faster | | string search | finding substrings | 2.8x faster | | closures | calling function values | 2.0x faster | | channel ping-pong | goroutine hand-off | 1.5x faster | | quicksort | branches and swaps | about equal | | tree building | allocation and garbage collection | 0.9x (slower) | | defer in a loop | `defer` cost | 0.7x (slower) | Where marmot wins big, the cause is usually vector instructions that Go's compiler does not emit. Where it loses, the cause is allocation and `defer`, which Go has tuned for years. ### Loops that can run in parallel [#loops-that-can-run-in-parallel] marmot can prove that the iterations of some loops do not depend on each other, and then run them on all cores. This is off by default while it is being reviewed. With it on: These use every core, so they are faster in wall-clock time, not in total CPU work. ## Binary size [#binary-size] hello world with println, -release148 KB1.68 MBhello world with fmt.Println, -release665 KB2.4 MBhello world with println, -O z100 KB1.17 MB (stripped)small program using fmt, sort, strings, a map500 KB1.62 MB (stripped)
Programmarmotgo
## Build time [#build-time] ### First build [#first-build] Building the compiler itself (`./cmd/marmot`, 238 packages including the standard library) from empty caches on both sides, measured 2026-11-13 10:46 on a quiet Apple M3 Pro:
Casemarmotgo
first build of cmd/marmot, empty caches5.13 to 5.43 s5.23 to 6.34 s
A first build compiles every package of the standard library the program uses. Rebuilds are where the build cache and the incremental front end pay off. ### Rebuilds [#rebuilds] The same tree and the same run (2026-11-13 10:46, 238 packages), with the incremental front end, the default. The edits add one line to a package: "leaf" is the main package, "deep" is a package that most of the compiler uses. Each case ran twice for each compiler, alternating. rebuild, nothing changed0.05 to 0.07 s0.14 to 0.15 sone line edit, leaf package0.68 to 0.70 s0.50 to 0.51 sone line edit, deep package0.94 to 0.96 s0.90 to 0.93 s
Casemarmotgo
A rebuild with nothing changed is where the build cache pays off. Dev builds use a fast code generator that writes machine code directly, without LLVM (`MARMOT_TIER0=0` turns it off). It is never used with `-release`. ## Memory [#memory] On small programs marmot binaries use about half the memory of Go binaries at run time, mostly because the runtime starts fewer things up front. ## How to reproduce [#how-to-reproduce] ```sh make go run ./bench/cmd/bench -list # see the programs go run ./bench/cmd/bench # run them go run ./bench/report # write the report ``` Run benchmarks on an idle machine. Other work on the same machine changes the results a lot. # Build modes (/docs/build-modes) There are two modes, because fast rebuilds and deep optimization pull in opposite directions. | Mode | Command | Use it for | | --- | --- | --- | | dev (default) | `marmot build` | Day to day work. Each package is compiled on its own and cached. | | release | `marmot build -release` | Shipping. The whole program is optimized together. Builds take longer. | ## Dev builds [#dev-builds] Each package is compiled separately and cached, so an edit recompiles little. Three things make dev builds fast: - **A fast code generator.** Dev builds write machine code directly, without LLVM. Its code is not optimized. `MARMOT_TIER0=0` uses LLVM instead: slower builds, faster code. - **Background optimization.** After a dev build returns, the packages it compiled are compiled again with LLVM at `-O2` on idle cores, and later builds link those optimized objects. `MARMOT_TIER1=0` turns this off. - **An incremental front end.** Rebuilds type check and compile only the changed packages and the packages that import them. `MARMOT_INCREMENTAL=0` turns it off. ## Release builds [#release-builds] The optimizer sees the whole program, which allows inlining across packages and removal of code that nothing uses. Release builds use `-O3` and every specialization. `MARMOT_RELEASE=1` makes `-release` the default. | Flag | Effect | | --- | --- | | `-O z` | Optimize for size: the smallest binary. | | `-O s` | Optimize for size, less aggressively. | | `-s` | Leave out file and line tables. Smaller, but panics show no source lines. | | `-pgo-gen`, `-pgo file` | Profile guided optimization. | The smallest possible binary: ```sh marmot build -release -O z -s -o app ./cmd/app ``` ## Numbers [#numbers] | | dev | release | go | | --- | --- | --- | --- | | hello world with `println` | | 148 KB | 1.68 MB | | hello world with `fmt.Println` | | 665 KB | 2.4 MB | | run time, 43 programs | 1.4x faster with `MARMOT_TIER0=0` | 1.6x faster | 1.0x | See [Benchmarks](/docs/benchmarks) for the method. ## Environment variables [#environment-variables] | Variable | Meaning | | --- | --- | | `MARMOT_RELEASE=1` | Make `-release` the default. | | `MARMOT_TIER0=0` | Dev builds use LLVM instead of the fast code generator. | | `MARMOT_TIER1=0` | Turn off background optimization of dev builds. | | `MARMOT_INCREMENTAL=0` | Turn off the incremental front end. | | `MARMOT_CACHE_MAX_MB` | Size cap of the build cache in megabytes (default 4096). | | `GOMAXPROCS`, `GOGC` | As in Go. | # cgo (/docs/cgo) cgo support is new. Cross builds of cgo packages are not supported yet. Packages that `import "C"` build unchanged. marmot runs `cmd/cgo` and compiles the generated code and the package's `.c`, `.s` and `.S` files with clang. `#cgo CFLAGS`, `LDFLAGS` and `pkg-config` lines work, and are checked against the same allowlists as the go command. ```go package main /* #include #include static int twice(int x) { return 2 * x; } */ import "C" import ( "fmt" "unsafe" ) func main() { s := C.CString("marmot") defer C.free(unsafe.Pointer(s)) fmt.Println(C.strlen(s), C.twice(21)) } ``` ## Cheaper calls [#cheaper-calls] A call to a C function is a direct native call with the C ABI, on the goroutine's own stack. There is no argument frame and no switch to another stack. The runtime is told when a goroutine enters and leaves C so the scheduler can keep other goroutines running; for functions marked with both `#cgo noescape` and `#cgo nocallback`, and for libc leaf functions, even that is reduced to a mark.
cost of one call to an empty C functionmarmotgo (cgo)
linux/amd64, -release2.3 ns33 to 57 ns
In release builds the C code is compiled to LLVM bitcode and optimized together with the Go code, so small C functions can be inlined into Go. ## What works [#what-works] - C functions, variables, constants, structs, unions, arrays, enums and function pointers. - `C.CString`, `C.GoString`, `C.GoStringN`, `C.GoBytes`, `C.CBytes`, `C.malloc` and `C.free`. - The `errno` second result. - `//export`: C calling Go, including nested calls, blocking callbacks and threads created in C. - `marmot test` of cgo packages. - Blocking C calls do not stop other goroutines. ## Not yet [#not-yet] - Cross builds (`-target`) of cgo packages. A fault inside a C call stops the program with a fatal error. # marmot bench (/docs/commands/bench) Build a package's benchmarks with marmot, run them several times, and report the median and spread of each. -vs go also builds them with go test and runs both alternately, then reports the change and its significance (Mann-Whitney U, benchstat style). -save keeps the raw results; -compare FILE compares with them. ```text title="Usage" marmot bench [package] [flags] ``` ## Examples [#examples] ```sh marmot bench -vs go ./... marmot bench -bench Fib -count 10 . marmot bench -save old.txt . && marmot bench -compare old.txt . ``` `marmot bench -vs go ./pkg` builds the package's benchmarks with marmot and with `go test`, runs them alternately (`-count`, default 6), and prints the median and spread of each, the change and whether it is significant (Mann-Whitney U, as benchstat does). Benchmarks are built at `-O 2` unless you give a level or `-release`. A benchmark under 1 ns per iteration gets a note: the optimizer probably removed work whose result was unused. `-cpuprofile FILE` profiles the last run; read it with [marmot prof](/docs/commands/prof). ```sh marmot bench -vs go -cpuprofile cpu.out ./pkg marmot prof -tree cpu.out ``` ## Flags [#flags] Flags take one dash or two: `-release` and `--release` are the same. | Flag | Meaning | | --- | --- | | `-bench string` | regexp of the benchmarks to run (default ".") | | `-benchtime string` | time or iterations per benchmark run, as -test.benchtime | | `-color string` | color in human output: auto, always or never (NO_COLOR turns auto off) (default "auto") | | `-compare string` | compare with results saved by -save (or any go test -bench output) | | `-count string` | runs of each benchmark (more runs, smaller p-values) (default "6") | | `-cpuprofile string` | write a CPU profile of the last run to this file (with -vs go, the go build's to FILE.go); read it with marmot prof | | `-json` | machine readable output: JSON Lines on stderr (also $MARMOT_OUTPUT=json, and the default under coding agents) | | `-save string` | write the raw results to this file | | `-timeout string` | time limit of each benchmark binary run (default "30m") | | `-vs string` | go: also run the benchmarks built by go test and compare | ## Full help [#full-help] ```text title="marmot bench --help" Build a package's benchmarks with marmot, run them several times, and report the median and spread of each. -vs go also builds them with go test and runs both alternately, then reports the change and its significance (Mann-Whitney U, benchstat style). -save keeps the raw results; -compare FILE compares with them. Usage: marmot bench [package] [flags] Examples: marmot bench -vs go ./... marmot bench -bench Fib -count 10 . marmot bench -save old.txt . && marmot bench -compare old.txt . Flags: --bench string regexp of the benchmarks to run (default ".") --benchtime string time or iterations per benchmark run, as -test.benchtime --color string color in human output: auto, always or never (NO_COLOR turns auto off) (default "auto") --compare string compare with results saved by -save (or any go test -bench output) --count string runs of each benchmark (more runs, smaller p-values) (default "6") --cpuprofile string write a CPU profile of the last run to this file (with -vs go, the go build's to FILE.go); read it with marmot prof -h, --help help for bench --json machine readable output: JSON Lines on stderr (also $MARMOT_OUTPUT=json, and the default under coding agents) --save string write the raw results to this file --timeout string time limit of each benchmark binary run (default "30m") --vs string go: also run the benchmarks built by go test and compare ``` # marmot build (/docs/commands/build) Compile the named main package (default: the current directory) into an executable. ```text title="Usage" marmot build [packages] [flags] ``` ## Examples [#examples] ```sh marmot build -o app ./cmd/app marmot build -release ./cmd/app marmot build -target linux/amd64 -o app-linux . ``` ## Build modes [#build-modes] `marmot build` has two modes. Dev builds (the default) compile each package on its own and cache it, so a rebuild after an edit compiles little. `-release` optimizes the whole program together at `-O3`: slower to build, smaller and faster to run. See [Build modes](/docs/build-modes). ## Common recipes [#common-recipes] Smallest possible binary: ```sh marmot build -release -O z -s -o app ./cmd/app ``` Build for Linux from a Mac: ```sh marmot build -target linux/amd64 -o app-linux ./cmd/app ``` Profile guided optimization: build an instrumented binary, run it, then build again with the merged profile: ```sh marmot build -pgo-gen -o app ./cmd/app ./app # writes marmot-.profraw next to itself llvm-profdata merge -o app.profdata marmot-*.profraw marmot build -release -pgo app.profdata -o app ./cmd/app ``` Stop early and look at the compiler's output with `-emit mlir`, `-emit llvm` or `-emit obj`. ## Allocation report [#allocation-report] `marmot build -allocs` prints, for each allocation in the main module that goes to the heap, where it is, what it allocates and why it could not stay in the stack frame. `-allocs-all` does the same for every package, the standard library included. Packages are compiled again for the report, so the build cache does not hide them. The reason is the first use that makes the value escape: returned, stored in a global or in memory that outlives the function, passed to a call that may keep it, captured by a closure, sent on a channel, converted to an interface, or too large for the frame. A heap allocation inside a loop gets a note, since it happens once per iteration. Each site is a diagnostic with code [M0111](/docs/diagnostics/codes/m0111). `MARMOT_ALLOC_REPORT=FILE` writes the raw decisions of any build, stack sites included, one JSON object per line: ```json {"fn":"example.com/ad.newPoint","pos":"/src/ad/main.go:9:47","kind":"composite","type":"point","bytes":16,"where":"heap","reason":"returned from the function (line 9)","final":true} ``` `where` is `stack`, `heap`, `region` (in the caller's region, freed when the caller is done) or `static`. `final` is false when the back end may still change the decision. ## The build cache [#the-build-cache] Compiled packages are cached, so a rebuild with no changes does almost no work. The cache is capped at 4 GB by default and old entries are removed automatically. Set `MARMOT_CACHE_MAX_MB` to change the cap; `marmot cache` shows its size, `marmot cache trim` and `marmot cache clean` shrink or remove it. ## Flags [#flags] Flags take one dash or two: `-release` and `--release` are the same. | Flag | Meaning | | --- | --- | | `-O string` | optimization level: 0, 1, 2, 3, s, z (default 2, 3 with -release) | | `-allocs` | report the allocation sites of the main module: heap or stack, and why (rebuilds without the object cache) | | `-allocs-all` | like -allocs, for every package | | `-color string` | color in human output: auto, always or never (NO_COLOR turns auto off) (default "auto") | | `-dialect string` | MLIR dialect level: llvm or go (default: go with -release, llvm otherwise; $MARMOT_DIALECT overrides) | | `-emit string` | output kind: mlir, llvm, obj, exe (default "exe") | | `-gc string` | garbage collector: precise or none (default "precise") | | `-json` | machine readable output: JSON Lines on stderr (also $MARMOT_OUTPUT=json, and the default under coding agents) | | `-nocache` | do not use the object cache | | `-o string` | output file | | `-pgo string` | profile guided optimization with this indexed profile (llvm-profdata merge -o FILE *.profraw) | | `-pgo-gen` | build an instrumented binary that writes marmot-.profraw next to itself | | `-release` | release build: whole program optimization, -O3, all specializations (default from $MARMOT_RELEASE=1) | | `-s` | omit the pc table (tracebacks without file:line) | | `-tags string` | comma separated build tags | | `-target string` | target triple (default: host) | | `-trace string` | traceback detail of -release builds: full keeps the inlined frames of each call site apart (as dev builds do) | | `-v` | print progress and timing | | `-work` | print and keep the temporary work directory | | `-x` | print the commands run | ## Full help [#full-help] ```text title="marmot build --help" Compile the named main package (default: the current directory) into an executable. Usage: marmot build [packages] [flags] Examples: marmot build -o app ./cmd/app marmot build -release ./cmd/app marmot build -target linux/amd64 -o app-linux . Flags: --O string optimization level: 0, 1, 2, 3, s, z (default 2, 3 with -release) --allocs report the allocation sites of the main module: heap or stack, and why (rebuilds without the object cache) --allocs-all like -allocs, for every package --color string color in human output: auto, always or never (NO_COLOR turns auto off) (default "auto") --dialect string MLIR dialect level: llvm or go (default: go with -release, llvm otherwise; $MARMOT_DIALECT overrides) --emit string output kind: mlir, llvm, obj, exe (default "exe") --gc string garbage collector: precise or none (default "precise") -h, --help help for build --json machine readable output: JSON Lines on stderr (also $MARMOT_OUTPUT=json, and the default under coding agents) --nocache do not use the object cache --o string output file --pgo string profile guided optimization with this indexed profile (llvm-profdata merge -o FILE *.profraw) --pgo-gen build an instrumented binary that writes marmot-.profraw next to itself --release release build: whole program optimization, -O3, all specializations (default from $MARMOT_RELEASE=1) --s omit the pc table (tracebacks without file:line) --tags string comma separated build tags --target string target triple (default: host) --trace string traceback detail of -release builds: full keeps the inlined frames of each call site apart (as dev builds do) --v print progress and timing --work print and keep the temporary work directory --x print the commands run ``` # marmot check (/docs/commands/check) Check the workspace (every module of go.work, or the current module) the way gofmt, goimports, go vet, golangci-lint (with .golangci.yml when present), go fix, govulncheck, go mod tidy, cross builds and deadcode would, on one package graph in one process. Results are cached per package, so an unchanged tree is answered at once and an edit reanalyzes only what it affects. Prints one line per finding and one line per check; exits 1 when a gating check fails (modernize and deadcode only report). ```text title="Usage" marmot check [packages] [flags] ``` ## Examples [#examples] ```sh marmot check marmot check -changed marmot check -changed main -only vet,lint marmot check -json ./internal/... ``` `marmot check` runs the checks a project usually runs one by one in CI, in one process over one package graph. With no packages it checks every module of the `go.work`, or the current module. | Check | Reports | Fails the run | | --- | --- | --- | | `fmt` | files gofmt or goimports would change | yes | | `vet` | the analyzers of the installed `go vet` | yes | | `lint` | the golangci-lint standard set (staticcheck, errcheck, govet, ineffassign, unused) and the gosec file permission rules; reads a v2 `.golangci.yml` | yes | | `gopls` | what `gopls check` reports | yes | | `vuln` | vulnerabilities the code calls, as govulncheck finds them | yes | | `tidy` | a `go.mod` or `go.sum` that `go mod tidy` would change | yes | | `cross` | type errors on other targets: `-targets`, `scripts/platforms.txt` or `platforms.txt`, else linux, darwin and windows on amd64 and arm64 | yes | | `modernize` | what the `go fix` modernizers would change | no | | `exhaustive` | switches that miss values of an enum or types of a sealed interface; runs only when `-only` names it or `.golangci.yml` enables it | no | | `nil` | dereferences of pointers and writes to maps that can be nil | no | | `deadcode` | functions no program or test reaches | no | `-only` picks checks; `-changed [REF]` checks only the packages whose files changed since REF (by default `origin/main`, else `main`): ```sh marmot check -changed -only vet,lint ``` ## Caching [#caching] Results are cached per package, keyed by its files and what its dependencies export, so an unchanged tree answers at once and an edit reanalyzes only what it affects (`-nocache` turns this off). On a workspace of 10 modules and 204 packages, the full set takes 46 s from an empty cache (251 s for the same tools run one by one), 0.7 s when nothing changed and about 1 s after an edit, and stays under 2 GB of memory. ## JSON [#json] In JSON mode each finding is a `diagnostic` object with `check` and `analyzer` fields (codes [M0100](/docs/diagnostics/codes/m0100) to [M0110](/docs/diagnostics/codes/m0110)), then one `{"kind":"check","check":"lint","status":"failed","findings":3,...}` object per check, then the `result` line. ## Flags [#flags] Flags take one dash or two: `-release` and `--release` are the same. | Flag | Meaning | | --- | --- | | `-changed string` | check only what changed against a git ref (-changed alone: origin/main, else main) | | `-color string` | color in human output: auto, always or never (NO_COLOR turns auto off) (default "auto") | | `-details` | show every finding with its source and suggested fix | | `-j string` | parallel analysis jobs (default: the number of CPUs) (default "0") | | `-json` | machine readable output: JSON Lines on stderr (also $MARMOT_OUTPUT=json, and the default under coding agents) | | `-nocache` | analyze everything again, ignoring cached results | | `-offline` | no network: the vulnerability check is skipped | | `-only string` | run only these checks, comma separated: fmt,vet,lint,modernize,gopls,exhaustive,nil,vuln,tidy,cross,deadcode | | `-staged` | check exactly what git has staged (for a pre-commit hook), not the working tree | | `-tags string` | comma separated build tags | | `-targets string` | cross build targets, comma separated goos/goarch (default: scripts/platforms.txt, else linux, darwin and windows on amd64 and arm64) | | `-v` | print timing and cache statistics | | `-watch` | run again after every change to the files and report only new and resolved findings | ## Full help [#full-help] ```text title="marmot check --help" Check the workspace (every module of go.work, or the current module) the way gofmt, goimports, go vet, golangci-lint (with .golangci.yml when present), go fix, govulncheck, go mod tidy, cross builds and deadcode would, on one package graph in one process. Results are cached per package, so an unchanged tree is answered at once and an edit reanalyzes only what it affects. Prints one line per finding and one line per check; exits 1 when a gating check fails (modernize and deadcode only report). Usage: marmot check [packages] [flags] Examples: marmot check marmot check -changed marmot check -changed main -only vet,lint marmot check -json ./internal/... Flags: --changed string check only what changed against a git ref (-changed alone: origin/main, else main) --color string color in human output: auto, always or never (NO_COLOR turns auto off) (default "auto") --details show every finding with its source and suggested fix -h, --help help for check --j string parallel analysis jobs (default: the number of CPUs) (default "0") --json machine readable output: JSON Lines on stderr (also $MARMOT_OUTPUT=json, and the default under coding agents) --nocache analyze everything again, ignoring cached results --offline no network: the vulnerability check is skipped --only string run only these checks, comma separated: fmt,vet,lint,modernize,gopls,exhaustive,nil,vuln,tidy,cross,deadcode --staged check exactly what git has staged (for a pre-commit hook), not the working tree --tags string comma separated build tags --targets string cross build targets, comma separated goos/goarch (default: scripts/platforms.txt, else linux, darwin and windows on amd64 and arm64) --v print timing and cache statistics --watch run again after every change to the files and report only new and resolved findings ``` # marmot doctor (/docs/commands/doctor) Check what marmot needs (its code generator and runtime, the go command, LLVM, the system linker), the build cache and free disk, how output is chosen here, and on macOS whether new binaries start slowly; print what to fix. ```text title="Usage" marmot doctor [flags] ``` ## Examples [#examples] ```sh marmot doctor marmot doctor -json ``` Run it first when something does not work. Each check prints a status and, when it fails, the command or setting that fixes it. `-json` writes one `doctor` object per check (`check`, `status`, `detail`, `fix`) and a `result`. ## Flags [#flags] Flags take one dash or two: `-release` and `--release` are the same. | Flag | Meaning | | --- | --- | | `-color string` | color in human output: auto, always or never (NO_COLOR turns auto off) (default "auto") | | `-json` | machine readable output: JSON Lines on stderr (also $MARMOT_OUTPUT=json, and the default under coding agents) | ## Full help [#full-help] ```text title="marmot doctor --help" Check what marmot needs (its code generator and runtime, the go command, LLVM, the system linker), the build cache and free disk, how output is chosen here, and on macOS whether new binaries start slowly; print what to fix. Usage: marmot doctor [flags] Examples: marmot doctor marmot doctor -json Flags: --color string color in human output: auto, always or never (NO_COLOR turns auto off) (default "auto") -h, --help help for doctor --json machine readable output: JSON Lines on stderr (also $MARMOT_OUTPUT=json, and the default under coding agents) ``` # marmot explain (/docs/commands/explain) Show what an error code means, an example of the mistake and the fix. With no code, list all codes. ```text title="Usage" marmot explain [CODE] [flags] ``` ## Examples [#examples] ```sh marmot explain M0014 marmot explain -json M0002 ``` Every diagnostic marmot prints has a stable code, such as `M0014`. `marmot explain CODE` says what it means, shows code with the mistake and the same code fixed, and gives the usual fix. With no code it lists all of them. `-json CODE` writes `{code, title, text, wrong, right, fix}` to stdout. Every code is on the [error codes](/docs/diagnostics/codes) page. ## Flags [#flags] Flags take one dash or two: `-release` and `--release` are the same. | Flag | Meaning | | --- | --- | | `-color string` | color in human output: auto, always or never (NO_COLOR turns auto off) (default "auto") | | `-json` | machine readable output: JSON Lines on stderr (also $MARMOT_OUTPUT=json, and the default under coding agents) | ## Full help [#full-help] ```text title="marmot explain --help" Show what an error code means, an example of the mistake and the fix. With no code, list all codes. Usage: marmot explain [CODE] [flags] Examples: marmot explain M0014 marmot explain -json M0002 Flags: --color string color in human output: auto, always or never (NO_COLOR turns auto off) (default "auto") -h, --help help for explain --json machine readable output: JSON Lines on stderr (also $MARMOT_OUTPUT=json, and the default under coding agents) ``` # marmot fix (/docs/commands/fix) Build, apply every machine applicable fix (missing imports, unused imports and variables, := with no new variables, ...), and build again until no fix applies. -all adds fixes that may be incorrect, such as typo corrections. ```text title="Usage" marmot fix [packages] [flags] ``` ## Examples [#examples] ```sh marmot fix marmot fix -code M0005 ./cmd/app marmot fix -all ``` `marmot fix` applies the machine applicable fixes of build errors, then those of the `fmt` and `modernize` checks. After each round it type checks the changed packages and undoes the fixes of any package that no longer builds; `-test` also requires their tests to pass. - `-code M0004,M0005` limits it to those build error codes. - `-all` adds fixes that may be incorrect, such as typo corrections and vet or lint suggestions. - `-only fmt,modernize` applies only those check fixes. - `-diff` prints the patches and changes nothing. - `-upgrade go1.N` raises the module's go version first. ```sh marmot fix -diff -only modernize ``` Every fix carries an applicability: `machine-applicable` (safe to apply unseen), `maybe-incorrect` (likely, check it) or `has-placeholders` (never applied as is). Plain `marmot fix` applies only the first kind. ## Flags [#flags] Flags take one dash or two: `-release` and `--release` are the same. | Flag | Meaning | | --- | --- | | `-all` | also apply fixes that may be incorrect (typo corrections); check the result | | `-code string` | only apply fixes for these comma separated codes, for example M0004,M0005 | | `-color string` | color in human output: auto, always or never (NO_COLOR turns auto off) (default "auto") | | `-diff` | print the check fixes as patches, change nothing | | `-json` | machine readable output: JSON Lines on stderr (also $MARMOT_OUTPUT=json, and the default under coding agents) | | `-only string` | apply only the fixes of these checks (fmt, modernize, vet, lint, exhaustive), not the build errors | | `-tags string` | comma separated build tags | | `-test` | keep a check fix only if the tests of its package still pass | | `-upgrade string` | raise the go version of the modules to go1.N and apply the modernizers it unlocks | ## Full help [#full-help] ```text title="marmot fix --help" Build, apply every machine applicable fix (missing imports, unused imports and variables, := with no new variables, ...), and build again until no fix applies. -all adds fixes that may be incorrect, such as typo corrections. Usage: marmot fix [packages] [flags] Examples: marmot fix marmot fix -code M0005 ./cmd/app marmot fix -all Flags: --all also apply fixes that may be incorrect (typo corrections); check the result --code string only apply fixes for these comma separated codes, for example M0004,M0005 --color string color in human output: auto, always or never (NO_COLOR turns auto off) (default "auto") --diff print the check fixes as patches, change nothing -h, --help help for fix --json machine readable output: JSON Lines on stderr (also $MARMOT_OUTPUT=json, and the default under coding agents) --only string apply only the fixes of these checks (fmt, modernize, vet, lint, exhaustive), not the build errors --tags string comma separated build tags --test keep a check fix only if the tests of its package still pass --upgrade string raise the go version of the modules to go1.N and apply the modernizers it unlocks ``` # marmot fmt (/docs/commands/fmt) Format the Go files of the named packages, files or dir/... trees the way goimports does: gofmt layout, missing imports added, unused imports removed. Files are rewritten in place and listed, like go fmt. -l only lists, -d prints a diff, -check exits 1 when a file is not formatted. ```text title="Usage" marmot fmt [files or packages] [flags] ``` ## Examples [#examples] ```sh marmot fmt marmot fmt ./... marmot fmt -d main.go marmot fmt -check ./... ``` `marmot fmt` formats the files `go fmt` would: those of the packages' directories, leaving out `testdata` and directories that start with `_` or `.`. It is the `fmt` check of [marmot check](/docs/commands/check), so the two never disagree. ## Flags [#flags] Flags take one dash or two: `-release` and `--release` are the same. | Flag | Meaning | | --- | --- | | `-check` | change nothing; exit 1 if a file is not formatted | | `-color string` | color in human output: auto, always or never (NO_COLOR turns auto off) (default "auto") | | `-d` | print a diff of the changes instead of writing them | | `-json` | machine readable output: JSON Lines on stderr (also $MARMOT_OUTPUT=json, and the default under coding agents) | | `-l` | only list the files that would change | ## Full help [#full-help] ```text title="marmot fmt --help" Format the Go files of the named packages, files or dir/... trees the way goimports does: gofmt layout, missing imports added, unused imports removed. Files are rewritten in place and listed, like go fmt. -l only lists, -d prints a diff, -check exits 1 when a file is not formatted. Usage: marmot fmt [files or packages] [flags] Examples: marmot fmt marmot fmt ./... marmot fmt -d main.go marmot fmt -check ./... Flags: --check change nothing; exit 1 if a file is not formatted --color string color in human output: auto, always or never (NO_COLOR turns auto off) (default "auto") --d print a diff of the changes instead of writing them -h, --help help for fmt --json machine readable output: JSON Lines on stderr (also $MARMOT_OUTPUT=json, and the default under coding agents) --l only list the files that would change ``` # marmot generate (/docs/commands/generate) Run the //go:generate directives of the named packages like go generate, and cache what each one writes, keyed by the directive, its environment, the generator binary and the package's other files. A directive whose inputs did not change has its outputs restored instead of running again. -n lists directives and whether they are cached; -force runs everything. ```text title="Usage" marmot generate [packages] [flags] ``` ## Examples [#examples] ```sh marmot generate ./... marmot generate -n ./... marmot generate -run stringer . ``` `marmot generate ./...` runs `//go:generate` directives like `go generate`, and remembers what each one wrote, keyed by the directive, its environment, the generator binary and the package's other files. When none of those changed, the outputs are restored instead of running the generator. `-n` lists directives and whether they are cached; `-force` runs everything. `-json` writes one `generate` object per directive (`command`, `cached`, `outputs`) and a `result`. ## Flags [#flags] Flags take one dash or two: `-release` and `--release` are the same. | Flag | Meaning | | --- | --- | | `-color string` | color in human output: auto, always or never (NO_COLOR turns auto off) (default "auto") | | `-force` | run every directive, ignoring the cache | | `-json` | machine readable output: JSON Lines on stderr (also $MARMOT_OUTPUT=json, and the default under coding agents) | | `-n` | print the directives and whether they are cached; run nothing | | `-run string` | only directives whose text contains this | | `-v` | print each directive as it runs | ## Full help [#full-help] ```text title="marmot generate --help" Run the //go:generate directives of the named packages like go generate, and cache what each one writes, keyed by the directive, its environment, the generator binary and the package's other files. A directive whose inputs did not change has its outputs restored instead of running again. -n lists directives and whether they are cached; -force runs everything. Usage: marmot generate [packages] [flags] Examples: marmot generate ./... marmot generate -n ./... marmot generate -run stringer . Flags: --color string color in human output: auto, always or never (NO_COLOR turns auto off) (default "auto") --force run every directive, ignoring the cache -h, --help help for generate --json machine readable output: JSON Lines on stderr (also $MARMOT_OUTPUT=json, and the default under coding agents) --n print the directives and whether they are cached; run nothing --run string only directives whose text contains this --v print each directive as it runs ``` # Commands (/docs/commands) marmot follows the `go` command where it can. Run it inside a Go module. | Command | What it does | | --- | --- | | [`marmot build`](/docs/commands/build) | Compile packages and their dependencies into an executable. | | [`marmot run`](/docs/commands/run) | Compile and run a program. | | [`marmot test`](/docs/commands/test) | Compile and run package tests, like go test. | | [`marmot check`](/docs/commands/check) | Run vet, lint, format and the other code checks in one pass. | | [`marmot fix`](/docs/commands/fix) | Apply the suggested fixes of build errors and check findings. | | [`marmot fmt`](/docs/commands/fmt) | Format Go source and fix its imports, as goimports does. | | [`marmot watch`](/docs/commands/watch) | Build, run or test again after every change. | | [`marmot repl`](/docs/commands/repl) | Evaluate Go declarations, statements and expressions interactively. | | [`marmot size`](/docs/commands/size) | Size of a binary by section, package and function. | | [`marmot bench`](/docs/commands/bench) | Run benchmarks and compare them with go or a saved run. | | [`marmot prof`](/docs/commands/prof) | Read a CPU or memory profile in the terminal. | | [`marmot doctor`](/docs/commands/doctor) | Check the installation and the environment and say what to fix. | | [`marmot explain`](/docs/commands/explain) | Describe an error code. | | [`marmot mcp`](/docs/commands/mcp) | Serve build, run, test, fix and explain to coding agents. | | [`marmot generate`](/docs/commands/generate) | Run //go:generate directives, with their outputs cached. | | `marmot cache` | Show the build cache size; `cache trim` and `cache clean` shrink or remove it. | | `marmot completion SHELL` | Print shell completion for bash, zsh, fish or powershell. | | `marmot version` | Print the version. | ## Top level help [#top-level-help] ```text title="marmot --help" marmot compiles Go programs to native executables through MLIR and LLVM. It works like the go command: run it inside a Go module. Errors are shown with the source, the exact span, and suggested fixes on a terminal, as plain file:line:col lines otherwise, and as JSON Lines with -json or MARMOT_OUTPUT=json (the default under coding agents). Usage: marmot [command] Examples: # build the package in the current directory marmot build # build and run a program with arguments marmot run ./cmd/app -v input.txt # smallest release binary marmot build -release -O z -s -o app ./cmd/app # apply the suggested fixes of the build errors marmot fix # what an error code means marmot explain M0002 Available Commands: bench Run benchmarks and compare them with go or a saved run bind Generate Go bindings from a C header build Compile packages and their dependencies cache Show, trim or remove the build cache check Run every code check in one pass: fmt, vet, lint, modernize, vuln, tidy, cross, deadcode completion Generate the autocompletion script for the specified shell doctor Check the toolchain, runtime, cache and environment explain Describe an error code fix Apply the suggested fixes of build errors fmt Format Go source and fix its imports (gofmt plus goimports) generate Run //go:generate directives, with their outputs cached help Help about any command mcp Serve marmot's tools to coding agents (Model Context Protocol) prof Read a CPU or memory profile in the terminal repl Evaluate Go interactively run Compile and run a Go program size Show what an executable's size is made of test Compile and run package tests version Print the marmot version watch Rebuild, rerun or retest on every change Flags: -h, --help help for marmot -v, --version version for marmot Use "marmot [command] --help" for more information about a command. ``` # marmot mcp (/docs/commands/mcp) Speak the Model Context Protocol on stdin and stdout, exposing build, run, test, fix and explain as tools that return marmot's JSON diagnostics. Register it with an agent, for example: claude mcp add marmot -- marmot mcp ```text title="Usage" marmot mcp [flags] ``` ## Examples [#examples] ```sh marmot mcp ``` `marmot mcp` is a Model Context Protocol server on stdin and stdout. Its tools `build`, `run`, `test`, `fix` and `explain` take a directory and return the [JSON output](/docs/diagnostics/json) that marmot writes in agent mode. To register it with Claude Code: ```sh claude mcp add marmot -- marmot mcp ``` Agents that run marmot as a plain command get JSON too: when a coding agent's environment variable is set, JSON is the default output. See [Diagnostics](/docs/diagnostics). ## Flags [#flags] Flags take one dash or two: `-release` and `--release` are the same. | Flag | Meaning | | --- | --- | | `-timeout string` | time limit of one tool call (default "5m0s") | ## Full help [#full-help] ```text title="marmot mcp --help" Speak the Model Context Protocol on stdin and stdout, exposing build, run, test, fix and explain as tools that return marmot's JSON diagnostics. Register it with an agent, for example: claude mcp add marmot -- marmot mcp Usage: marmot mcp [flags] Examples: marmot mcp Flags: -h, --help help for mcp --timeout string time limit of one tool call (default "5m0s") ``` # marmot prof (/docs/commands/prof) Show a pprof profile (from marmot bench -cpuprofile, go test -cpuprofile, or runtime/pprof): the top functions by cost, the hottest path, the call tree as a text flame graph (-tree), or the source of functions with the cost of each line (-list). -json gives agents the same data. ```text title="Usage" marmot prof PROFILE [flags] ``` ## Examples [#examples] ```sh marmot prof cpu.out marmot prof -tree cpu.out marmot prof -list 'parse.*' cpu.out marmot prof -sample alloc_space mem.out ``` `marmot prof` reads any pprof CPU or memory profile: the functions with the most cost (flat and cumulative), the hottest path, `-tree` for the call tree as a text flame graph, `-list REGEXP` for the source of matching functions with the cost of each line, `-sample alloc_space` and friends for memory profiles, and `-json` for programs. Programs built by marmot record CPU profiles with the standard `runtime/pprof` API (`pprof.StartCPUProfile`), so the same profile can be read with `marmot prof` or `go tool pprof`. On Linux each thread is sampled on its own CPU clock; on macOS the process timer is used. ## Flags [#flags] Flags take one dash or two: `-release` and `--release` are the same. | Flag | Meaning | | --- | --- | | `-color string` | color in human output: auto, always or never (NO_COLOR turns auto off) (default "auto") | | `-json` | machine readable output: JSON Lines on stderr (also $MARMOT_OUTPUT=json, and the default under coding agents) | | `-list string` | show the source of functions matching this regexp, each line with its cost | | `-min string` | leave out tree nodes below this percentage of the total (default "1") | | `-n string` | how many functions to list (default "15") | | `-sample string` | sample type to show: cpu, samples, alloc_space, alloc_objects, inuse_space, ... (default: the profile's default) | | `-tree` | show the call tree (callers above callees) instead of the top list | ## Full help [#full-help] ```text title="marmot prof --help" Show a pprof profile (from marmot bench -cpuprofile, go test -cpuprofile, or runtime/pprof): the top functions by cost, the hottest path, the call tree as a text flame graph (-tree), or the source of functions with the cost of each line (-list). -json gives agents the same data. Usage: marmot prof PROFILE [flags] Examples: marmot prof cpu.out marmot prof -tree cpu.out marmot prof -list 'parse.*' cpu.out marmot prof -sample alloc_space mem.out Flags: --color string color in human output: auto, always or never (NO_COLOR turns auto off) (default "auto") -h, --help help for prof --json machine readable output: JSON Lines on stderr (also $MARMOT_OUTPUT=json, and the default under coding agents) --list string show the source of functions matching this regexp, each line with its cost --min string leave out tree nodes below this percentage of the total (default "1") --n string how many functions to list (default "15") --sample string sample type to show: cpu, samples, alloc_space, alloc_objects, inuse_space, ... (default: the profile's default) --tree show the call tree (callers above callees) instead of the top list ``` # marmot repl (/docs/commands/repl) Read Go declarations, statements and expressions and run them as you type, on the incremental build. Expressions print their value; imports of the standard library are added when you use a package. Tab or the right arrow accepts the completion shown in grey. Commands: :type EXPR, :doc NAME, :time, :imports, :reset, :quit. ```text title="Usage" marmot repl [flags] ``` ## Examples [#examples] ```sh marmot repl echo 'strings.Repeat("ab", 3)' | marmot repl ``` `marmot repl` reads Go one entry at a time. An expression prints its value, a statement runs, a `func` or `type` declaration is kept for later entries. Packages of the standard library are imported when you use them (`strings.ToUpper("a")` just works); `import "example.com/x"` adds others. History is kept in `~/.marmot_history`. | Command | What it does | | --- | --- | | `:type EXPR` | Print the type of an expression. | | `:doc NAME` | Print the documentation of a name. | | `:time` | Time each entry. | | `:imports` | List the imports in effect. | | `:reset` | Forget every entry. | | `:quit` | Leave. | Each entry is compiled and run as a whole program with the entries before it, and only the new output is shown. Earlier statements run again each time, so their side effects repeat. An entry that does not compile or panics is not kept. ## Flags [#flags] Flags take one dash or two: `-release` and `--release` are the same. | Flag | Meaning | | --- | --- | | `-time` | print how long each entry took to build and run | ## Full help [#full-help] ```text title="marmot repl --help" Read Go declarations, statements and expressions and run them as you type, on the incremental build. Expressions print their value; imports of the standard library are added when you use a package. Tab or the right arrow accepts the completion shown in grey. Commands: :type EXPR, :doc NAME, :time, :imports, :reset, :quit. Usage: marmot repl [flags] Examples: marmot repl echo 'strings.Repeat("ab", 3)' | marmot repl Flags: -h, --help help for repl --time print how long each entry took to build and run ``` # marmot run (/docs/commands/run) Build the program in a temporary directory and run it with the arguments that follow the package or the .go files. Its exit status is marmot's. ```text title="Usage" marmot run package|files... [arguments] [flags] ``` ## Examples [#examples] ```sh marmot run main.go marmot run ./cmd/app -port 8080 ``` The program is built in a temporary directory with the same flags as `marmot build`, then run with the arguments that follow the package or the files. Build errors are shown the same way as for `marmot build`. A panic in the program is reported in the same three modes as build errors: on a terminal the report lists the program's frames with their source lines and folds library frames; in JSON mode it is one `panic` object (code [M0020](/docs/diagnostics/codes/m0020)). See [Runtime errors](/docs/diagnostics#runtime-errors). ## Flags [#flags] Flags take one dash or two: `-release` and `--release` are the same. | Flag | Meaning | | --- | --- | | `-O string` | optimization level: 0, 1, 2, 3, s, z (default 2, 3 with -release) | | `-allocs` | report the allocation sites of the main module: heap or stack, and why (rebuilds without the object cache) | | `-allocs-all` | like -allocs, for every package | | `-color string` | color in human output: auto, always or never (NO_COLOR turns auto off) (default "auto") | | `-dialect string` | MLIR dialect level: llvm or go (default: go with -release, llvm otherwise; $MARMOT_DIALECT overrides) | | `-emit string` | output kind: mlir, llvm, obj, exe (default "exe") | | `-gc string` | garbage collector: precise or none (default "precise") | | `-json` | machine readable output: JSON Lines on stderr (also $MARMOT_OUTPUT=json, and the default under coding agents) | | `-nocache` | do not use the object cache | | `-o string` | output file | | `-pgo string` | profile guided optimization with this indexed profile (llvm-profdata merge -o FILE *.profraw) | | `-pgo-gen` | build an instrumented binary that writes marmot-.profraw next to itself | | `-release` | release build: whole program optimization, -O3, all specializations (default from $MARMOT_RELEASE=1) | | `-s` | omit the pc table (tracebacks without file:line) | | `-tags string` | comma separated build tags | | `-target string` | target triple (default: host) | | `-trace string` | traceback detail of -release builds: full keeps the inlined frames of each call site apart (as dev builds do) | | `-v` | print progress and timing | | `-work` | print and keep the temporary work directory | | `-x` | print the commands run | ## Full help [#full-help] ```text title="marmot run --help" Build the program in a temporary directory and run it with the arguments that follow the package or the .go files. Its exit status is marmot's. Usage: marmot run package|files... [arguments] [flags] Examples: marmot run main.go marmot run ./cmd/app -port 8080 Flags: --O string optimization level: 0, 1, 2, 3, s, z (default 2, 3 with -release) --allocs report the allocation sites of the main module: heap or stack, and why (rebuilds without the object cache) --allocs-all like -allocs, for every package --color string color in human output: auto, always or never (NO_COLOR turns auto off) (default "auto") --dialect string MLIR dialect level: llvm or go (default: go with -release, llvm otherwise; $MARMOT_DIALECT overrides) --emit string output kind: mlir, llvm, obj, exe (default "exe") --gc string garbage collector: precise or none (default "precise") -h, --help help for run --json machine readable output: JSON Lines on stderr (also $MARMOT_OUTPUT=json, and the default under coding agents) --nocache do not use the object cache --o string output file --pgo string profile guided optimization with this indexed profile (llvm-profdata merge -o FILE *.profraw) --pgo-gen build an instrumented binary that writes marmot-.profraw next to itself --release release build: whole program optimization, -O3, all specializations (default from $MARMOT_RELEASE=1) --s omit the pc table (tracebacks without file:line) --tags string comma separated build tags --target string target triple (default: host) --trace string traceback detail of -release builds: full keeps the inlined frames of each call site apart (as dev builds do) --v print progress and timing --work print and keep the temporary work directory --x print the commands run ``` # marmot size (/docs/commands/size) Break an executable down by section, by package and by function, and show what calls a function (-why). Function names and sizes come from marmot's pc table, or from the symbol table for other binaries. ```text title="Usage" marmot size BINARY [flags] ``` ## Examples [#examples] ```sh marmot size ./app marmot size -pkg fmt ./app marmot size -why fmt.Sprintf ./app ``` `marmot size app` lists the sections of the executable, the code of each package and the largest functions. `-pkg fmt` lists one package's functions; `-why fmt.Sprintf` prints a chain of direct calls from `main` to the function, which says why it is linked in. It also reads binaries built by other compilers, through their symbol table. `-json` writes one `size` object with `sections`, `packages` and `functions`; with `-why` it has `why` with `chain`. ## Flags [#flags] Flags take one dash or two: `-release` and `--release` are the same. | Flag | Meaning | | --- | --- | | `-color string` | color in human output: auto, always or never (NO_COLOR turns auto off) (default "auto") | | `-json` | machine readable output: JSON Lines on stderr (also $MARMOT_OUTPUT=json, and the default under coding agents) | | `-n string` | how many packages and functions to list (default "15") | | `-pkg string` | list the functions of this package only | | `-why string` | show a chain of direct calls from main to this function | ## Full help [#full-help] ```text title="marmot size --help" Break an executable down by section, by package and by function, and show what calls a function (-why). Function names and sizes come from marmot's pc table, or from the symbol table for other binaries. Usage: marmot size BINARY [flags] Examples: marmot size ./app marmot size -pkg fmt ./app marmot size -why fmt.Sprintf ./app Flags: --color string color in human output: auto, always or never (NO_COLOR turns auto off) (default "auto") -h, --help help for size --json machine readable output: JSON Lines on stderr (also $MARMOT_OUTPUT=json, and the default under coding agents) --n string how many packages and functions to list (default "15") --pkg string list the functions of this package only --why string show a chain of direct calls from main to this function ``` # marmot test (/docs/commands/test) Build the test binary of each package and run it, like go test. Test flags (-run, -v, -count, -bench, ...) go to the test binary. With -json, every test and failure is reported as JSON Lines. ```text title="Usage" marmot test [packages] [flags] ``` ## Examples [#examples] ```sh marmot test ./... marmot test -run TestParse -v . ``` On a terminal `marmot test` shows each failure first, at the line of its `t.Error` or `t.Fatal` with the source, then every test and subtest with its status and time, then a summary. Off a terminal the output is the same as `go test`, so CI scripts that parse it keep working. `marmot test -watch` runs the tests again after every change. `marmot test -json` writes one `{"kind":"test", "package", "name", "status", "durationMs", "file", "line", "message", "output"}` line per test and subtest, a `diagnostic` (code [M0022](/docs/diagnostics/codes/m0022)) per failure with its source context, and the result. ## Flags [#flags] Flags take one dash or two: `-release` and `--release` are the same. | Flag | Meaning | | --- | --- | | `-O string` | optimization level: 0, 1, 2, 3, s, z | | `-color string` | color in human output: auto, always or never (NO_COLOR turns auto off) (default "auto") | | `-dialect string` | MLIR dialect level: llvm or go | | `-json` | machine readable output: JSON Lines on stderr (also $MARMOT_OUTPUT=json, and the default under coding agents) | | `-o string` | write the test binary here and do not run it | | `-release` | release build | | `-tags string` | comma separated build tags | | `-work` | print and keep the temporary work directory | | `-x` | print the commands run | ## Full help [#full-help] ```text title="marmot test --help" Build the test binary of each package and run it, like go test. Test flags (-run, -v, -count, -bench, ...) go to the test binary. With -json, every test and failure is reported as JSON Lines. Usage: marmot test [packages] [flags] Examples: marmot test ./... marmot test -run TestParse -v . Flags: --O string optimization level: 0, 1, 2, 3, s, z --color string color in human output: auto, always or never (NO_COLOR turns auto off) (default "auto") --dialect string MLIR dialect level: llvm or go -h, --help help for test --json machine readable output: JSON Lines on stderr (also $MARMOT_OUTPUT=json, and the default under coding agents) --o string write the test binary here and do not run it --release release build --tags string comma separated build tags --work print and keep the temporary work directory --x print the commands run ``` # marmot watch (/docs/commands/watch) Build now and after every change to a .go file, go.mod or go.sum of the module, using the build cache so only what changed is compiled again. With run, the program is stopped and started again; with test, the tests run again. The screen is cleared before each round on a terminal. Watch flags (-interval, -clear) come first; the other flags go to the build. ```text title="Usage" marmot watch [build|run|test] [packages] [flags] ``` ## Examples [#examples] ```sh marmot watch marmot watch run ./cmd/server -port 8080 marmot watch test -run TestParse ./... ``` `marmot watch` builds the current package now and again after every change to a `.go` file, `go.mod` or `go.sum`. `marmot watch run ./cmd/server -port 8080` stops the program and starts the new build after each change; `marmot watch test ./...` runs the tests again. The screen is cleared before each round on a terminal (`-clear=false` keeps the scrollback); `-interval` sets how often files are checked. Rebuilds go through the build cache, so only what changed is compiled again. `marmot watch -generate` runs [marmot generate](/docs/commands/generate) before every build. ## Flags [#flags] Flags take one dash or two: `-release` and `--release` are the same. | Flag | Meaning | | --- | --- | | `-clear` | clear the screen before each build (terminal only) (default true) | | `-color string` | color in human output: auto, always or never (NO_COLOR turns auto off) (default "auto") | | `-generate` | run marmot generate (cached) before each build | | `-interval string` | how often to look for changed files (default "300ms") | | `-json` | machine readable output: JSON Lines on stderr (also $MARMOT_OUTPUT=json, and the default under coding agents) | ## Full help [#full-help] ```text title="marmot watch --help" Build now and after every change to a .go file, go.mod or go.sum of the module, using the build cache so only what changed is compiled again. With run, the program is stopped and started again; with test, the tests run again. The screen is cleared before each round on a terminal. Watch flags (-interval, -clear) come first; the other flags go to the build. Usage: marmot watch [build|run|test] [packages] [flags] Examples: marmot watch marmot watch run ./cmd/server -port 8080 marmot watch test -run TestParse ./... Flags: --clear clear the screen before each build (terminal only) (default true) --color string color in human output: auto, always or never (NO_COLOR turns auto off) (default "auto") --generate run marmot generate (cached) before each build -h, --help help for watch --interval string how often to look for changed files (default "300ms") --json machine readable output: JSON Lines on stderr (also $MARMOT_OUTPUT=json, and the default under coding agents) ``` # Design (/docs/design) marmot reuses the parts of the Go toolchain that define the language, and replaces the parts that generate code. ## Pipeline [#pipeline] 1. **Front end.** The standard `go/types` checker and the `x/tools` SSA builder turn source into a simple, typed instruction form. Generic code is expanded here. 2. **MLIR.** Each package becomes an MLIR module. Plain operations use MLIR's `llvm` dialect. Operations that carry Go meaning use a small `go` dialect. 3. **Go-aware passes.** These run while the program still says "allocate a slice" or "call through an interface", which makes some optimizations much easier than on LLVM IR. 4. **LLVM.** The module is lowered to LLVM IR, optimized, and turned into machine code. All of this happens inside one backend process. 5. **Link.** Objects are linked with the runtime by the system linker. Unused code is removed. ## What lowering looks like [#what-lowering-looks-like] One function, captured at each level with `marmot build -emit mlir`, `-emit llvm` and `-emit obj`. The marked parts are what changed at that level. ```go title="Go" // [!code word:range xs] func Sum(xs []int32) int32 { var s int32 for _, x := range xs { s += x } return s } ``` In MLIR the loop still says what Go means: `go.index` is an index into a slice, with its bounds check. ```text title="MLIR, with the go dialect" // [!code word:go.index] %v9 = llvm.extractvalue %a0[0] : !llvm.struct<(ptr, i64, i64)> %v10 = llvm.extractvalue %a0[1] : !llvm.struct<(ptr, i64, i64)> %v11 = go.index %v9[%v7] len %v10, i32 : i64 %v12 = llvm.load %v11 {alignment = 4 : i64, go.unsafe} : !llvm.ptr -> i32 %v13 = llvm.add %v1, %v12 : i32 ``` In LLVM IR at `-O 2` the check is gone and the loop works on four `int32` values at a time. ```text title="LLVM IR" // [!code word:<4 x i32>] %wide.load = load <4 x i32>, ptr %5, align 4 %wide.load12 = load <4 x i32>, ptr %6, align 4 %wide.load13 = load <4 x i32>, ptr %7, align 4 %wide.load14 = load <4 x i32>, ptr %8, align 4 %9 = add <4 x i32> %wide.load, %vec.phi ``` On arm64 that is two 128 bit loads and four vector adds each time round. ```text title="arm64" // [!code word:add.4s] ldp q4, q5, [x8, #-0x20] ldp q6, q7, [x8], #0x40 add.4s v0, v4, v0 add.4s v1, v5, v1 add.4s v2, v6, v2 add.4s v3, v7, v3 ``` ## Why a Go dialect [#why-a-go-dialect] LLVM sees memory, branches and calls. It does not know that a branch is a bounds check, or that a call allocates. The `go` dialect keeps that knowledge long enough to use it. | Group | Examples | What the passes do with it | | --- | --- | --- | | Allocation | `new`, `make`, closures, boxing | Keep objects on the stack when they do not outlive the function. | | Indexing | index, slice, bounds and nil checks | Remove checks that can be shown never to fail. | | Interfaces | interface calls, type assertions | Call the method directly when the type is known. | | Control | `defer`, `panic`, `go` | Make `defer` cheap when no panic can reach it. | | Strings | concatenation, conversions | Join concatenations, avoid copies when safe. | | Loops | counted loops over slices | Vectorize, and run independent iterations in parallel. | ## Build modes [#build-modes] In dev mode each package is compiled separately and cached, so an edit recompiles little. In release mode the optimizer sees the whole program, which allows inlining across packages and removal of code that nothing uses. See [Build modes](/docs/build-modes). ## Runtime [#runtime] Every binary carries a small runtime in two layers. | Part | How it works | | --- | --- | | Garbage collector | Mark and sweep. It does not move objects. Marking runs on several threads. | | Goroutines | Each has its own stack. Many goroutines share a few OS threads, and idle threads take work from busy ones. | | Channels | Unbuffered channels hand values directly to the waiting goroutine. Buffered channels use a lock-free ring. | | Maps | Open addressing in groups, with fast paths for integer and string keys. | | Panics | `defer`, `panic` and `recover` follow Go's rules, including stack traces with file and line. | | Library fast paths | Byte search, UTF-8, hex, base64, CRC and SHA-2 use vector instructions where the CPU has them. | The standard library is Go's own source. marmot replaces only the packages that are tied to Go's runtime or written in assembly. ## Keeping it correct [#keeping-it-correct] A fast compiler is only useful if its output is right. marmot is checked in three ways. - **Comparison with Go.** A suite of several hundred programs is built with both compilers, and the output and exit status must match. A fuzzer generates more programs at random. - **Review of every optimization.** Each optimization is switched on by default only after its rule is written down and it passes the whole suite with the optimization forced on. - **Proofs.** The rules behind the riskier optimizations (bounds check removal, loop parallelization, object lifetimes) are proved in Bend 2 and Lean 4, and a separate checker re-examines what the compiler actually did. ## Repository layout [#repository-layout] | Path | Contents | | --- | --- | | `cmd/marmot` | The command line tool. | | `internal/` | Front end: loading, code generation to MLIR, build driver. | | `backend/` | C++ backend: the `go` dialect, passes, LLVM lowering. | | `runtime/core/` | C part of the runtime. | | `lib/src/` | Go part of the runtime and replaced standard library packages. | | `tests/` | Conformance programs and the tools that run them. | | `bench/` | Benchmark programs and runner. | | `verify/` | Proofs and checkers. | # Error codes (/docs/diagnostics/codes) Every diagnostic has a stable code. `marmot explain CODE` prints the same description in the terminal, and `marmot explain -json CODE` as JSON. ## Build errors [#build-errors] | Code | What it means | | --- | --- | | [M0000](/docs/diagnostics/codes/m0000) | error | | [M0001](/docs/diagnostics/codes/m0001) | syntax error | | [M0002](/docs/diagnostics/codes/m0002) | undefined name | | [M0003](/docs/diagnostics/codes/m0003) | no such field or method | | [M0004](/docs/diagnostics/codes/m0004) | declared and not used | | [M0005](/docs/diagnostics/codes/m0005) | imported and not used | | [M0006](/docs/diagnostics/codes/m0006) | type mismatch | | [M0007](/docs/diagnostics/codes/m0007) | mismatched types | | [M0008](/docs/diagnostics/codes/m0008) | wrong number of return values | | [M0009](/docs/diagnostics/codes/m0009) | wrong number of arguments | | [M0010](/docs/diagnostics/codes/m0010) | missing return | | [M0011](/docs/diagnostics/codes/m0011) | package not found | | [M0012](/docs/diagnostics/codes/m0012) | assignment count mismatch | | [M0013](/docs/diagnostics/codes/m0013) | no new variables | | [M0014](/docs/diagnostics/codes/m0014) | does not implement interface | | [M0015](/docs/diagnostics/codes/m0015) | redeclared | | [M0016](/docs/diagnostics/codes/m0016) | invalid operation | | [M0017](/docs/diagnostics/codes/m0017) | bad command line | | [M0018](/docs/diagnostics/codes/m0018) | link error | | [M0019](/docs/diagnostics/codes/m0019) | internal compiler error | | [M0020](/docs/diagnostics/codes/m0020) | runtime panic | | [M0021](/docs/diagnostics/codes/m0021) | fatal runtime error | | [M0022](/docs/diagnostics/codes/m0022) | test failed | | [M0023](/docs/diagnostics/codes/m0023) | import cycle | | [M0024](/docs/diagnostics/codes/m0024) | name not exported | | [M0025](/docs/diagnostics/codes/m0025) | not supported by marmot | | [M0026](/docs/diagnostics/codes/m0026) | type argument does not satisfy constraint | | [M0027](/docs/diagnostics/codes/m0027) | cannot infer type argument | | [M0028](/docs/diagnostics/codes/m0028) | shadowed variable | | [M0029](/docs/diagnostics/codes/m0029) | unknown struct field | ## Check findings and reports [#check-findings-and-reports] | Code | What it means | | --- | --- | | [M0100](/docs/diagnostics/codes/m0100) | vet finding | | [M0101](/docs/diagnostics/codes/m0101) | lint finding | | [M0102](/docs/diagnostics/codes/m0102) | modernize suggestion | | [M0103](/docs/diagnostics/codes/m0103) | not formatted | | [M0104](/docs/diagnostics/codes/m0104) | gopls finding | | [M0105](/docs/diagnostics/codes/m0105) | known vulnerability | | [M0106](/docs/diagnostics/codes/m0106) | go.mod not tidy | | [M0107](/docs/diagnostics/codes/m0107) | cross build failure | | [M0108](/docs/diagnostics/codes/m0108) | unreachable function | | [M0109](/docs/diagnostics/codes/m0109) | switch misses cases | | [M0110](/docs/diagnostics/codes/m0110) | possible nil dereference | | [M0111](/docs/diagnostics/codes/m0111) | heap allocation | # M0000 error (/docs/diagnostics/codes/m0000) The message says what is wrong. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0001 syntax error (/docs/diagnostics/codes/m0001) The position is where the parser gave up, which is often just after the real mistake: look at the end of the previous line for a missing bracket, comma or operand. ## The mistake and the fix [#the-mistake-and-the-fix]
```go title="The mistake" func main() { x := 1 + } ``` ```go title="Fixed" func main() { x := 1 + 2 // [!code highlight] _ = x // [!code highlight] } ```
## The fix [#the-fix] Complete the expression or statement, or close the open bracket. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0002 undefined name (/docs/diagnostics/codes/m0002) It may be misspelled, declared in a file excluded by build tags, or belong to a package that is not imported. ## The mistake and the fix [#the-mistake-and-the-fix]
```go title="The mistake" fmt.Printn("hi") n := strings.Count(s, "a") // strings not imported ``` ```go title="Fixed" import "strings" // [!code highlight] fmt.Println("hi") // [!code highlight] n := strings.Count(s, "a") // [!code highlight] ```
## The fix [#the-fix] Fix the spelling, or import the package that declares it. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0003 no such field or method (/docs/diagnostics/codes/m0003) For methods, check the receiver: a method with a pointer receiver is not in the method set of the value type when the value is not addressable. ## The mistake and the fix [#the-mistake-and-the-fix]
```go title="The mistake" var b strings.Builder b.WriteStrin("x") ``` ```go title="Fixed" var b strings.Builder b.WriteString("x") // [!code highlight] ```
## The fix [#the-fix] Use one of the fields or methods of the type. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0004 declared and not used (/docs/diagnostics/codes/m0004) Assigning to a variable does not count as a use. ## The mistake and the fix [#the-mistake-and-the-fix]
```go title="The mistake" count := len(xs) // never read ``` ```go title="Fixed" // remove it, or use it: // [!code highlight] count := len(xs) // [!code highlight] fmt.Println(count) // [!code highlight] ```
## The fix [#the-fix] Use the variable, remove it, or assign the value to _. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0005 imported and not used (/docs/diagnostics/codes/m0005) ## The mistake and the fix [#the-mistake-and-the-fix]
```go title="The mistake" import "os" // nothing uses os ``` ```go title="Fixed" // remove the import, or for side effects only: // [!code highlight] import _ "net/http/pprof" // [!code highlight] ```
## The fix [#the-fix] Remove the import, or use _ as its name if it is imported only for its init side effects. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0006 type mismatch (/docs/diagnostics/codes/m0006) ## The mistake and the fix [#the-mistake-and-the-fix]
```go title="The mistake" func add(a, b int) int add(1, "two") ``` ```go title="Fixed" add(1, 2) // [!code highlight] ```
## The fix [#the-fix] Convert the value, or change the declaration of the destination. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0007 mismatched types (/docs/diagnostics/codes/m0007) ## The mistake and the fix [#the-mistake-and-the-fix]
```go title="The mistake" var n int var f float64 _ = n + f ``` ```go title="Fixed" _ = float64(n) + f // [!code highlight] ```
## The fix [#the-fix] Convert one operand to the type of the other. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0008 wrong number of return values (/docs/diagnostics/codes/m0008) ## The mistake and the fix [#the-mistake-and-the-fix]
```go title="The mistake" func main() { return 1 } ``` ```go title="Fixed" func f() int { // [!code highlight] return 1 } ```
## The fix [#the-fix] Return exactly the values in the signature, or change the signature. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0009 wrong number of arguments (/docs/diagnostics/codes/m0009) ## The mistake and the fix [#the-mistake-and-the-fix]
```go title="The mistake" func pair() (int, int) pair(1) ``` ```go title="Fixed" pair() // [!code highlight] ```
## The fix [#the-fix] Pass the arguments the signature lists. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0010 missing return (/docs/diagnostics/codes/m0010) ## The mistake and the fix [#the-mistake-and-the-fix]
```go title="The mistake" func sign(x int) int { if x < 0 { return -1 } } ``` ```go title="Fixed" func sign(x int) int { if x < 0 { return -1 } return 1 // [!code highlight] } ```
## The fix [#the-fix] Add a return at the end, or a panic for a case that cannot happen. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0011 package not found (/docs/diagnostics/codes/m0011) ## The mistake and the fix [#the-mistake-and-the-fix]
```go title="The mistake" import "example.com/lib" // not in go.mod ``` ```go title="Fixed" // go get example.com/lib, then // [!code highlight] import "example.com/lib" // [!code highlight] ```
## The fix [#the-fix] Run go get for the module, fix the import path, or remove the import. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0012 assignment count mismatch (/docs/diagnostics/codes/m0012) ## The mistake and the fix [#the-mistake-and-the-fix]
```go title="The mistake" n := strconv.Atoi(s) ``` ```go title="Fixed" n, err := strconv.Atoi(s) // [!code highlight] if err != nil { // [!code highlight] return err // [!code highlight] } // [!code highlight] ```
## The fix [#the-fix] Receive every result, using _ for the ones you do not need. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0013 no new variables (/docs/diagnostics/codes/m0013) ## The mistake and the fix [#the-mistake-and-the-fix]
```go title="The mistake" x := 1 x := 2 ``` ```go title="Fixed" x := 1 x = 2 // [!code highlight] ```
## The fix [#the-fix] Use = instead of :=. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0014 does not implement interface (/docs/diagnostics/codes/m0014) ## The mistake and the fix [#the-mistake-and-the-fix]
```go title="The mistake" type Shape interface{ Area() float64 } type Square struct{ s float64 } func (q *Square) Area() float64 { return q.s * q.s } var s Shape = Square{2} ``` ```go title="Fixed" var s Shape = &Square{2} // *Square has Area // [!code highlight] ```
## The fix [#the-fix] Add the missing method, fix its signature, or pass a pointer when the method has a pointer receiver. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0015 redeclared (/docs/diagnostics/codes/m0015) ## The mistake and the fix [#the-mistake-and-the-fix]
```go title="The mistake" func f() {} func f() {} ``` ```go title="Fixed" func f() {} func g() {} // [!code highlight] ```
## The fix [#the-fix] Rename one of the declarations or remove the duplicate. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0016 invalid operation (/docs/diagnostics/codes/m0016) ## The mistake and the fix [#the-mistake-and-the-fix]
```go title="The mistake" var m, n map[string]int _ = m < n // maps have no order ``` ```go title="Fixed" _ = len(m) < len(n) // [!code highlight] ```
See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0017 bad command line (/docs/diagnostics/codes/m0017) See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0018 link error (/docs/diagnostics/codes/m0018) ## The fix [#the-fix] If the function comes from the standard library, marmot does not support it yet; report it. For your own code, give the function a body. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0019 internal compiler error (/docs/diagnostics/codes/m0019) This is a bug in marmot, not in your code. The report bundle has what is needed to reproduce it. ## The fix [#the-fix] Report the bug with the bundle. As a workaround try -O 0, or MARMOT_TIER0=0. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0020 runtime panic (/docs/diagnostics/codes/m0020) The trace lists the goroutine's frames, innermost first. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0021 fatal runtime error (/docs/diagnostics/codes/m0021) Fatal errors cannot be recovered. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0022 test failed (/docs/diagnostics/codes/m0022) See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0023 import cycle (/docs/diagnostics/codes/m0023) Go does not allow import cycles. Move the shared code into a third package that both import. ## The mistake and the fix [#the-mistake-and-the-fix]
```go title="The mistake" // package a imports b, package b imports a ``` ```go title="Fixed" // move what both need into package c; a and b import c // [!code highlight] ```
See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0024 name not exported (/docs/diagnostics/codes/m0024) ## The mistake and the fix [#the-mistake-and-the-fix]
```go title="The mistake" i := strings.indexFunc(s, unicode.IsSpace) ``` ```go title="Fixed" i := strings.IndexFunc(s, unicode.IsSpace) // [!code highlight] ```
## The fix [#the-fix] Use the exported name (upper case first letter). See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0025 not supported by marmot (/docs/diagnostics/codes/m0025) See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0026 type argument does not satisfy constraint (/docs/diagnostics/codes/m0026) For a ~T term, the underlying type of the argument must be T. ## The mistake and the fix [#the-mistake-and-the-fix]
```go title="The mistake" type Number interface{ ~int | ~float64 } func Sum[T Number](xs []T) T Sum([]float32{1}) ``` ```go title="Fixed" type Number interface{ ~int | ~float32 | ~float64 } // [!code highlight] func Sum[T Number](xs []T) T Sum([]float32{1}) ```
## The fix [#the-fix] Use a type in the set, or widen the constraint. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0027 cannot infer type argument (/docs/diagnostics/codes/m0027) Give the type argument explicitly. ## The mistake and the fix [#the-mistake-and-the-fix]
```go title="The mistake" func Zero[T any]() T x := Zero() ``` ```go title="Fixed" x := Zero[int]() // [!code highlight] ```
## The fix [#the-fix] Write the type arguments in brackets after the function name. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0028 shadowed variable (/docs/diagnostics/codes/m0028) Assignments go to the inner one, which is then unused, and the outer one keeps its old value. This often loses an error. ## The mistake and the fix [#the-mistake-and-the-fix]
```go title="The mistake" var err error if ok { data, err := load() // a new err use(data) } return err // always nil ``` ```go title="Fixed" var err error if ok { var data []byte // [!code highlight] data, err = load() // [!code highlight] use(data) } return err // [!code highlight] ```
## The fix [#the-fix] Declare the other variables first and assign with =. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0029 unknown struct field (/docs/diagnostics/codes/m0029) ## The mistake and the fix [#the-mistake-and-the-fix]
```go title="The mistake" u := User{Nmae: "ada"} ``` ```go title="Fixed" u := User{Name: "ada"} // [!code highlight] ```
## The fix [#the-fix] Use one of the struct's fields. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0100 vet finding (/docs/diagnostics/codes/m0100) The note names the analyzer. ## The fix [#the-fix] Follow the finding; marmot fix applies the machine applicable ones. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0101 lint finding (/docs/diagnostics/codes/m0101) The note names the analyzer (SA, S, ST and QF numbers follow staticcheck). ## The fix [#the-fix] Follow the finding, or silence it for one line with a //lint:ignore comment that says why. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0102 modernize suggestion (/docs/diagnostics/codes/m0102) Behavior is unchanged. ## The fix [#the-fix] marmot fix applies these. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0103 not formatted (/docs/diagnostics/codes/m0103) ## The fix [#the-fix] Run marmot fmt. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0104 gopls finding (/docs/diagnostics/codes/m0104) ## The fix [#the-fix] Follow the finding; marmot fix applies the machine applicable ones. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0105 known vulnerability (/docs/diagnostics/codes/m0105) Only vulnerabilities in reached code are reported. ## The fix [#the-fix] Upgrade the module to the fixed version the finding names. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0106 go.mod not tidy (/docs/diagnostics/codes/m0106) ## The fix [#the-fix] Run go mod tidy. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0107 cross build failure (/docs/diagnostics/codes/m0107) ## The fix [#the-fix] Add the missing implementation for that platform, or a build tag that excludes the package there. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0108 unreachable function (/docs/diagnostics/codes/m0108) ## The fix [#the-fix] Remove it, or use it. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0109 switch misses cases (/docs/diagnostics/codes/m0109) A value added to the enum later then goes unnoticed. ## The mistake and the fix [#the-mistake-and-the-fix]
```go title="The mistake" type Color int const (Red Color = iota; Green; Blue) switch c { case Red, Green: } ``` ```go title="Fixed" switch c { case Red, Green: case Blue: // [!code highlight] // handled, or nothing to do // [!code highlight] } ```
## The fix [#the-fix] Handle the missing values, add a default clause, or write //exhaustive:ignore on the line before the switch. marmot fix adds the missing cases with empty bodies, which keeps the behavior. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0110 possible nil dereference (/docs/diagnostics/codes/m0110) A use dominated by a nil check is not reported. ## The mistake and the fix [#the-mistake-and-the-fix]
```go title="The mistake" func find(id int) (*User, error) { if id == 0 { return nil, nil } ... } u, err := find(id) if err != nil { return err } fmt.Println(u.Name) // u is nil for id 0 ``` ```go title="Fixed" u, err := find(id) if err != nil { return err } if u == nil { // [!code highlight] return errNotFound // [!code highlight] } fmt.Println(u.Name) // [!code highlight] ```
## The fix [#the-fix] Check for nil before the use, or make the function return an error instead of nil, nil. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # M0111 heap allocation (/docs/diagnostics/codes/m0111) Heap allocations cost time in the allocator and the garbage collector; those in loops cost on every iteration. ## The mistake and the fix [#the-mistake-and-the-fix]
```go title="The mistake" func newPoint() *Point { return &Point{1, 2} // returned: heap } ``` ```go title="Fixed" func point() Point { // [!code highlight] return Point{1, 2} // a value: no allocation // [!code highlight] } ```
## The fix [#the-fix] Return values instead of pointers, pass buffers in, keep large arrays out of loops, or avoid interfaces on hot paths. See also [all error codes](/docs/diagnostics/codes) and [marmot explain](/docs/commands/explain). # Diagnostics (/docs/diagnostics) Every error has a stable code (`M0002`) that `marmot explain` describes. The same diagnostic is written in one of three modes: | Mode | When | What it looks like | | --- | --- | --- | | human | stderr is a terminal | `error[CODE]: message`, then `--> file:line:col`, the source with carets under the exact span and a label saying what is wrong there, labels on related spans, `= note:` and `= help:` lines, and fixes as `help:` with a diff. At most 10 errors, sorted by file and line, then a summary. | | plain | stderr is not a terminal | `file:line:col: message` lines, as the go tool prints them. Tools and tests parse this form; it does not change. | | json | `-json`, `MARMOT_OUTPUT=json`, or a coding agent environment | JSON Lines on stderr. See [JSON output](/docs/diagnostics/json). | `MARMOT_OUTPUT=human`, `plain` or `json` overrides the choice. `-color=auto|always|never` sets color in human mode; `auto` respects `NO_COLOR` and `TERM=dumb`. ## Human [#human] The parts, top to bottom: 1. The severity and code, then the message. 2. `-->` and the position of the primary span. 3. The source lines involved, with carets under the primary span and dashes under related spans, each with a label. Lines in between are folded as `...`. 4. `= note:` lines with what the compiler knows, such as the method a type lacks. 5. `help:` with a suggested fix shown as a diff. `(check it)` marks fixes that are likely but not certain. 6. A summary and the `marmot explain` command for the code. ## Plain [#plain] The same error off a terminal, for scripts and editors that parse `go build` output: ```text ./main.go:12:16: cannot use Square{…} (value of struct type Square) as Shape value in variable declaration: Square does not implement Shape (method Area has pointer receiver) ``` ## JSON for coding agents [#json-for-coding-agents] JSON is the default when one of these variables is set (to anything but `0`) and `MARMOT_OUTPUT` is not: `CLAUDECODE`, `AI_AGENT`, `CODEX_SANDBOX`, `GEMINI_CLI`, `CURSOR_AGENT`, `OPENCODE`, `GOOSE_TERMINAL`. Each diagnostic carries its spans, the enclosing function, the source lines around it, the fixes as edits, and `rendered`, the exact human form. An agent can apply a fix without opening the file. `marmot mcp` serves the same data over the Model Context Protocol. See [JSON output](/docs/diagnostics/json) for the schema, and [Error codes](/docs/diagnostics/codes) for every code. ## Runtime errors [#runtime-errors] A program built by marmot reports a panic or fatal error in the same three modes, chosen when it happens. - On a terminal the report lists the program's frames with their source lines and folds library frames. - Off a terminal the trace is the plain Go form. - With `MARMOT_OUTPUT=json` it writes one object: ```json {"schema":1, "kind":"panic", "code":"M0020", "message", "valueType", "chain", "goroutine", "frames":[{"func", "file", "line", "col", "inlined", "user"}], "goroutines":{"total", "running", "runnable", "waiting"}, "exitCode":2} ``` `kind` is `fatal` and the code `M0021` for fatal errors. `marmot run` in JSON mode passes `MARMOT_OUTPUT=json` to the program. # JSON output (/docs/diagnostics/json) Each line is one object with `"schema": 1` and a `kind`. A command writes zero or more `diagnostic` lines and ends with one `result` line. ```json {"schema":1,"kind":"diagnostic","severity":"error","code":"M0002","message":"undefined: fmt.Printn", "span":{"file":"/src/app/main.go","line":15,"col":6,"endLine":15,"endCol":12}, "help":["a func with a similar name exists: fmt.Println"], "fixes":[{"title":"use fmt.Println","edits":[{"file":"/src/app/main.go", "span":{"file":"/src/app/main.go","line":15,"col":6,"endLine":15,"endCol":12},"newText":"Println"}]}], "context":{"function":"func main()","lines":[{"line":15,"text":"\tfmt.Printn(\"x\")"}]}, "explain":"marmot explain M0002"} {"schema":1,"kind":"result","command":"build","ok":false,"errors":1,"warnings":0,"durationMs":310,"exitCode":1} ``` New fields may be added within schema 1; parsers must ignore fields they do not know. ## diagnostic [#diagnostic] | Field | Meaning | | --- | --- | | `severity` | `error`, `warning` or `note`. | | `label` | What is wrong at the primary span, readable on its own. | | `code` | Stable code, `M0000` when there is no more specific one. See [Error codes](/docs/diagnostics/codes). | | `message` | The message, as in plain mode. | | `span` | Primary location. Lines and columns are 1-based, columns count bytes, `endCol` is exclusive. Absent location: `file` is empty. | | `labels` | Secondary spans, each `{span, text}`. | | `notes`, `help` | Lists of strings. | | `fixes` | Suggested fixes, each `{title, applicability, edits}`; an edit is `{file, span, newText}` and replaces the span (an empty span inserts). `applicability` is `machine-applicable` (safe to apply unseen), `maybe-incorrect` (likely, check it) or `has-placeholders` (never apply as is). Applying every edit of one fix resolves the diagnostic. | | `related` | Other locations, each `{span, message}`, for example the declaration of a called function. | | `context` | What you would open the file for: `function` (enclosing signature), `lines` (source around the span, `{line, text}`), `types` (one line definitions of the types the message names). | | `bundle` | Internal compiler errors only: a directory with the inputs for a bug report. | | `rendered` | The human form without color, exactly what a person would see. | | `fullMessage` | Present when `message` was shortened (long type names elided). | | `explain` | The command that describes the code. | In JSON mode all errors are listed (no cap), duplicates removed, in a stable order. ## result [#result] `command`, `ok`, `errors`, `warnings`, `output` (the file written, on success), `durationMs`, `exitCode`. ## Other commands [#other-commands] Other commands use the same envelope (`schema`, `kind`) with their own kinds: | Command | Kinds | | --- | --- | | `marmot test -json` | `test` per test, `diagnostic` per failure, `result` | | `marmot fix -json` | `fix` per applied fix (`file`, `code`, `title`, `line`), then `diagnostic` and `result` | | `marmot fmt -json` | `format` per changed file (`file`, `written`), `result` | | `marmot generate -json` | `generate` per directive (`command`, `cached`, `outputs`), `result` | | `marmot watch -json` | `watch` events (`build`, `done`) around each round's own output | | `marmot size -json` | one `size` object: `sections`, `packages`, `functions`; `-why` gives `why` with `chain` | | `marmot bench -json` | `bench` per benchmark and unit, with the summaries, `delta` and `p` | | `marmot prof -json` | one `profile` object: `functions`, `lines`, and `tree` with `-tree` | | `marmot doctor -json` | `doctor` per check (`check`, `status`, `detail`, `fix`), `result` | | `marmot check -json` | `diagnostic` per finding with `check` and `analyzer`, `check` per check, `result` | | `marmot explain -json CODE` | `{code, title, text, wrong, right, fix}` on stdout | # FAQ (/docs/faq) ## Is marmot a fork of Go? [#is-marmot-a-fork-of-go] No. marmot uses Go's own type checker, SSA builder and standard library source, so it compiles the same language with the same library. It replaces the code generator, the linker step and the runtime: code goes through MLIR and LLVM, and the runtime is marmot's own. ## Do I need to change my code? [#do-i-need-to-change-my-code] No. marmot builds ordinary Go modules with `go.mod`, build tags, tests and `//go:generate`. The [known differences](/docs/support#known-differences-from-go) are cases the Go specification leaves open. ## Is it ready for production? [#is-it-ready-for-production] Not yet. It compiles real programs, including itself, and checks every test program's output against Go, but it is young. Use it where a wrong result is cheap to notice, and keep `go build` for what you ship until you have checked it on your code. ## Why are the binaries so small? [#why-are-the-binaries-so-small] The runtime is small and starts little up front, and release builds optimize the whole program together, so code that nothing calls is removed. `-O z` and `-s` make them smaller still. `marmot size -why FUNC` says why a function is in a binary. ## Why are some programs slower than with Go? [#why-are-some-programs-slower-than-with-go] Mostly allocation heavy code and `defer` in hot loops, which Go has tuned for years. See [Benchmarks](/docs/benchmarks#by-kind-of-program). ## Can I keep using go test, go vet and gopls? [#can-i-keep-using-go-test-go-vet-and-gopls] Yes. marmot does not change your module, so the go tools keep working next to it. `marmot test` and `marmot check` are there when you want one tool that does both. ## Does it work with coding agents? [#does-it-work-with-coding-agents] Yes. Under a coding agent marmot writes its diagnostics as JSON, with spans, source context and fixes as edits, and `marmot mcp` serves build, run, test, fix and explain over the Model Context Protocol. See [Diagnostics](/docs/diagnostics#json-for-coding-agents). ## Does it support cgo? [#does-it-support-cgo] Yes, as of recently: packages that import `"C"` build, and C calls are direct native calls. Cross builds of cgo packages do not work yet. See [cgo](/docs/cgo). ## Which platforms? [#which-platforms] macOS on Apple Silicon and Linux on x86-64. Linux on arm64 builds; Windows is not supported. ## Why the name? [#why-the-name] A marmot is a close relative of the gopher, and it starts with M, like MLIR. # Getting started (/docs/getting-started) This page assumes marmot is installed and `marmot doctor` reports no problems. If not, see [Install](/docs/install). ## Build and run [#build-and-run] marmot works on any Go module. Make one: ```sh mkdir hello && cd hello go mod init hello ``` ```go title="main.go" package main import "fmt" func main() { name := "marmot" fmt.Println("hello,", name) } ``` Run it, then build an executable. The commands are the go command's, with `marmot` in front: ```sh marmot run main.go marmot build -o hello . ./hello ``` ```sh go run main.go go build -o hello . ./hello ``` The first build compiles the standard library packages the program uses and caches them, so later builds are fast. For the binary you ship, use release mode: ```sh marmot build -release -o hello . ``` ## Read an error [#read-an-error] Change `Println` to `Printn` and build again. marmot shows the source, marks the exact span, says what is wrong there, and suggests a fix: The fix is marked `check it` because it is a guess based on the name. `marmot fix -all` applies it; plain `marmot fix` applies only fixes that are always safe, such as removing an unused import. `marmot explain M0002` describes the error with an example. Errors that involve more than one place point at each of them: ## Test [#test] `marmot test` runs package tests like `go test`. On a terminal each failure comes first, at the line of its `t.Error` or `t.Fatal`: ## Next [#next] - [Build modes](/docs/build-modes): dev and release, and what each is for. - [Commands](/docs/commands): every command, with its flags. - [Diagnostics](/docs/diagnostics): human, plain and JSON output, and every error code. # Introduction (/docs) marmot compiles Go programs to native executables through MLIR and LLVM. It works like the `go` command: run it inside a Go module, with the same packages, flags and tests. ```sh marmot build ./cmd/app # fast rebuilds marmot build -release ./cmd/app # whole program optimization marmot run main.go marmot test ./... ``` marmot compiles real Go programs, including itself, but it is new and not ready for production use. See [Support](/docs/support) for what works and what does not. ## Why marmot [#why-marmot] - **Small binaries.** A hello world with `println` is 148 KB in release mode, against 1.68 MB from `go build`. With `fmt.Println` it is 665 KB against 2.4 MB. - **Fast programs.** Release builds run 1.6x faster than Go on average over 43 programs, with every program's output checked against Go. - **Fast builds.** A rebuild with nothing changed takes 0.05 to 0.07 s on a 238 package program, against 0.14 to 0.15 s. - **Errors that teach.** Every error shows the source, the exact span, a label that says what is wrong there, and a suggested fix that `marmot fix` can apply. Coding agents get the same information as JSON. ## The tools you install next to go [#the-tools-you-install-next-to-go] marmot also does what people usually install separate tools for: `marmot fmt` (goimports), `marmot check` (vet, golangci-lint, govulncheck, tidy and more, in one pass), `marmot fix`, `marmot watch`, `marmot repl`, `marmot bench` (benchstat built in), `marmot prof` (pprof in the terminal), `marmot size`, `marmot generate` with a cache, `marmot doctor`, and `marmot mcp` for coding agents. See [Commands](/docs/commands). ## How it works [#how-it-works] marmot keeps the parts of the Go toolchain that define the language (the `go/types` checker, the SSA builder, Go's own standard library source) and replaces the parts that generate code. [Design](/docs/design) explains each step. ## The name [#the-name] A marmot is a close relative of the gopher, and it starts with M, like MLIR. Marmots stand guard on a rock and whistle when something is wrong, which is what marmot's error messages are for. # Install (/docs/install) marmot is built from source for now. There are no release binaries yet. ## Requirements [#requirements] | Tool | Version | | --- | --- | | Go | 1.27 | | LLVM and MLIR | 22 (clang, lld and the MLIR libraries) | | CMake and Ninja | recent | marmot runs on macOS on Apple Silicon and on Linux on x86-64. Linux on arm64 builds but is not yet tested; Windows is not supported. See [Support](/docs/support). ## Build and install [#build-and-install] ```sh git clone https://github.com/Gaurav-Gosain/marmot cd marmot make # the front end, the backend and the runtime make test # optional: the test suites make install # copies the compiler to ~/.marmot and links ~/.local/bin/marmot ``` `make install` copies the build, so rebuilding the source tree later does not change the installed compiler. `PREFIX` and `BINDIR` choose other places: ```sh make install PREFIX=/opt/marmot BINDIR=/usr/local/bin ``` ## Check the installation [#check-the-installation] ```sh marmot doctor ``` `marmot doctor` checks the code generator and runtime, the `go` command, LLVM, the system linker, the build cache and free disk, and says how output is chosen in this terminal. Every failed check comes with what to do about it. ## Shell completion [#shell-completion] ```sh marmot completion zsh > "${fpath[1]}/_marmot" marmot completion bash > /etc/bash_completion.d/marmot marmot completion fish > ~/.config/fish/completions/marmot.fish ``` # Support matrix (/docs/support-matrix) Generated from marmot's test results of 2026-11-12. Every test builds a program with marmot and with Go and compares the output and exit status. Status words: **works** (every test passes), **partial** (some fail), **missing** (not implemented), **untested**. ## Conformance numbers [#conformance-numbers] Every test compares stdout, stderr (up to the first panic line) and exit status with the stock Go toolchain. | Tier | Passing | Total | What it covers | | --- | --- | --- | --- | | run/core | 134 | 134 | language core, no imports, `println` only | | run/gc | 13 | 13 | allocation heavy programs | | run/sched | 15 | 15 | goroutines, channels, deadlock | | run/std | 235 | 238 | standard library by package | | run/opt | 21 | 22 | optimizer and specializer targets | | run/mem | 50 | 50 | use after free and lifetime hunting (every way a slice stays reachable) | | run/layout | 49 | 49 | struct layouts: every field mix, every access path | | run/audit | 33 | 41 | counterexamples from the spec and verify audits | | run/apps | 12 | 12 | 200 to 600 line real programs | | goroot | 98 | 108 | single file programs from the Go project's own test suite | | world | 29 | 32 | real open source modules (vendored, pinned) | | **total (dev build)** | **689** | **714** | | Other build modes in the same run: | Mode | Passing | Total | | --- | --- | --- | | dev | 689 | 714 | | gcstress | 50 | 50 | | lifetime | 49 | 50 | ## Language [#language] | Feature | Status | Tests | | --- | --- | --- | | Integers: wraparound, shifts, division, conversions | works | 13 of 13 | | Floats: NaN, infinities, conversions, printing | works | 6 of 6 Fused multiply-add follows gc on arm64. | | Complex numbers | works | 2 of 2 | | Strings, runes, UTF-8 iteration and conversion | works | 7 of 7 | | Slices: append, copy, aliasing, capacity | works | 10 of 10 Growth capacities may differ from gc. | | Arrays and structs: copy, compare, embedding | works | 9 of 9 | | Maps, all key kinds, iteration with deletion | works | 8 of 8 Iteration order is random, as in gc. | | Methods, method values and expressions | works | 2 of 2 | | Closures and Go 1.22 loop variables | works | 4 of 4 | | Interfaces, assertions, type switches | works | 12 of 12 | | Generics: functions, types, constraints | works | 5 of 5 | | defer, panic, recover | works | 18 of 18 | | Runtime panics: bounds, nil, divide, assertions | works | 8 of 8 Message text matches gc; the stack trace format differs. | | Control flow: labels, goto, switch, range over int and func | works | 10 of 10 | | Constants and iota | works | 2 of 2 | | Initialization order and init functions | works | 2 of 2 | | Evaluation order | works | 2 of 2 Variables are read after calls in the same expression, as gc does. | | Goroutines, channels, select | works | 26 of 26 | | Garbage collection (allocation heavy programs) | works | 13 of 13 | | unsafe | works | 5 of 5 | | Compiler optimizations preserve semantics | partial | 21 of 22 Loop, specialization and float tests; run at -O0, -O2, -Oz and -release. | | Real programs (parsers, interpreters, simulations) | works | 12 of 12 | | cgo | missing | non-goal for v1 | | Race detector (-race) | missing | non-goal for v1 | | plugin package | missing | non-goal for v1 | | DWARF debug info | missing | non-goal for v1 | | Windows | missing | non-goal for v1 | ## Standard library [#standard-library] Each row is a directory under `tests/run/std`. Packages not listed have no test yet. | Packages | Status | Tests | | --- | --- | --- | | sync/atomic | works | 10 of 10 | | bufio | works | 11 of 11 | | bytes | works | 10 of 10 | | compress/* | works | 1 of 1 | | encoding/{base32,base64,hex,binary,csv,xml,gob,asn1,pem,ascii85} | works | 4 of 4 | | errors | works | 10 of 10 | | path, path/filepath | works | 5 of 5 | | fmt | works | 14 of 14 | | container/{heap,list,ring} | works | 3 of 3 | | net/http, httptest, cookiejar, crypto/tls | works | 8 of 8 | | io | works | 11 of 11 | | encoding/json | works | 8 of 8 | | log | partial | 1 of 2 | | maps | works | 10 of 10 | | math, math/bits, math/cmplx | works | 12 of 12 | | net, net/netip | works | 6 of 6 | | os, os/user | works | 12 of 12 | | math/rand | works | 3 of 3 | | reflect | partial | 7 of 8 | | regexp | works | 6 of 6 | | runtime, runtime/debug | missing | 0 of 1 | | slices, cmp | works | 10 of 10 | | log/slog | works | 1 of 1 | | sort | works | 10 of 10 | | database/sql | works | 1 of 1 | | strconv | works | 10 of 10 | | strings | works | 10 of 10 | | sync | works | 12 of 12 | | text/template | works | 5 of 5 | | time, time/tzdata | works | 14 of 14 | | unicode, unicode/utf8, unicode/utf16 | works | 10 of 10 | ### Stock standard library tests under `marmot test` [#stock-standard-library-tests-under-marmot-test] Results of `marmot test -short` on stock packages (darwin/arm64 laptop, 2026-11-12, before the fixes). "alloc counts only" means every failure is a `testing.AllocsPerRun` count. | package | result | pass | fail | rate | | --- | --- | --- | --- | --- | | fmt | ok | 79 | 0 | 100% | | strings | FAIL | 146 | 5 | 97% | | bytes | FAIL | 175 | 3 | 98% | | strconv | FAIL | 69 | 11 | 86% | | sort | ok | 81 | 0 | 100% | | slices | FAIL | 162 | 3 | 98% | | maps | ok | 24 | 0 | 100% | | math | ok | 111 | 0 | 100% | | unicode | ok | 42 | 0 | 100% | | unicode/utf8 | FAIL | 30 | 1 | 97% | | time | FAIL | 46 | 2 | 96% | | sync | build | 0 | 0 | - | | sync/atomic | ok | 107 | 0 | 100% | | context | FAIL | 68 | 1 | 99% | | errors | ok | 92 | 0 | 100% | | io | FAIL | 77 | 2 | 97% | | bufio | FAIL | 88 | 1 | 99% | | os | FAIL | 3525 | 11 | 100% | | os/exec | FAIL | 23 | 57 | 29% | | os/signal | FAIL | 5 | 1 | 83% | | path | ok | 16 | 0 | 100% | | path/filepath | FAIL | 59 | 1 | 98% | | encoding/json | FAIL | 0 | 1 | 0% | | encoding/binary | build | 0 | 0 | - | | encoding/base64 | ok | 23 | 0 | 100% | | encoding/hex | ok | 18 | 0 | 100% | | encoding/csv | ok | 77 | 0 | 100% | | encoding/xml | FAIL | 332 | 3 | 99% | | encoding/pem | ok | 21 | 0 | 100% | | regexp | ok | 75 | 0 | 100% | | text/template | FAIL | 58 | 1 | 98% | | html/template | FAIL | 0 | 0 | - | | text/tabwriter | ok | 6 | 0 | 100% | | text/scanner | ok | 22 | 0 | 100% | | net/url | FAIL | 89 | 5 | 95% | | net/http | build | 0 | 0 | - | | net/http/httptest | FAIL | 51 | 3 | 94% | | net | FAIL | 9 | 0 | 100% | | mime | FAIL | 24 | 1 | 96% | | mime/multipart | FAIL | 49 | 4 | 92% | | crypto/sha256 | FAIL | 33 | 2 | 94% | | crypto/md5 | FAIL | 17 | 1 | 94% | | crypto/sha1 | FAIL | 17 | 1 | 94% | | crypto/hmac | ok | 233 | 0 | 100% | | crypto/rand | FAIL | 14 | 2 | 88% | | crypto/aes | ok | 58 | 0 | 100% | | crypto/tls | FAIL | 0 | 0 | - | | crypto/x509 | FAIL | 0 | 0 | - | | hash/crc32 | ok | 18 | 0 | 100% | | hash/fnv | ok | 62 | 0 | 100% | | container/heap | ok | 9 | 0 | 100% | | container/list | ok | 11 | 0 | 100% | | container/ring | ok | 15 | 0 | 100% | | math/rand | FAIL | 25 | 2 | 93% | | math/rand/v2 | ok | 25 | 0 | 100% | | math/big | FAIL | 266 | 1 | 100% | | math/bits | build | 0 | 0 | - | | reflect | build | 0 | 0 | - | | runtime | build | 0 | 0 | - | | log | FAIL | 9 | 2 | 82% | | log/slog | FAIL | 225 | 29 | 89% | | flag | FAIL | 28 | 1 | 97% | | embed | build | 0 | 0 | - | | io/fs | FAIL | 5 | 0 | 100% | | compress/gzip | ok | 23 | 0 | 100% | | compress/flate | ok | 128 | 0 | 100% | | archive/tar | FAIL | 1 | 2 | 33% | | archive/zip | FAIL | 0 | 0 | - | | html | ok | 6 | 0 | 100% | | go/token | FAIL | 25 | 1 | 96% | | go/scanner | ok | 25 | 0 | 100% | | go/parser | FAIL | 42 | 0 | 100% | | go/ast | FAIL | 23 | 1 | 96% | | go/format | ok | 5 | 0 | 100% | | go/types | FAIL | 70 | 1 | 99% | | iter | FAIL | 10 | 10 | 50% | | unique | build | 0 | 0 | - | ## Real world modules [#real-world-modules] Vendored at a pinned version under `tests/world` (see `tests/world/README.md`), each with a small deterministic program checked against stock Go. | Module test | Status | | --- | --- | | base58 | works | | blackfriday | works | | cobra | works | | decimal | works | | difflib | works | | doublestar | works | | embedfs | works | | fuzzysearch | works | | gjson | works | | gocmp | works | | godiff | works | | goldmark | works | | gotoml | works | | govaluate | works | | humanize | works | | ini | works | | levenshtein | works | | lru | works | | mapstructure | fails | | pflag | works | | pkgerrors | works | | rate | works | | semver | works | | strcase | works | | tablewriter | works | | testify | fails | | toml | works | | ulid | fails | | uuid | works | | xtext | works | | xxhash | works | | yaml | works | 29 of 32 world programs pass. ## Build modes [#build-modes] - **dev** (default, `-O2`): the safe pipeline; every transform below that is marked off stays off. - **`-release`**: whole program optimization, `-O3`, loop and library specializations. - **`-O0` `-O1` `-O2` `-O3` `-Os` `-Oz`**: LLVM level; the conformance runner can run any program in `-O0`, `-O2`, `-Oz` and `-release` (`-modes`). - **Opt-in lifetime and memory transforms**, each behind an environment switch. A transform is on by default only after a proof review and a full conformance matrix plus fuzz round with it forced on; until then it is off. | Transform | Switch | Default | | --- | --- | --- | | In-place reuse (reuse.go) | MARMOT_REUSE | off | | Capture by value (escape.go allocSettled) | MARMOT_BYVALUE | off | | Region inference (region.go) | MARMOT_REGIONS | off | | Frame regions (frameregion.go) | MARMOT_FRAME_REGIONS | off | | Allocation sinking (allocsink.go) | MARMOT_ALLOCSINK | off | | Escape summaries, cross package, extended rules | MARMOT_ESCAPE_SUMMARY, MARMOT_XPKG_ESCAPE, MARMOT_ESCAPE_EXT | off | | Conversion and make frame buffers (stackconv.go) | MARMOT_STACKCONV | off | | Intraprocedural escape (default path) | on | on | | go-strings S3 no-copy (backend) | -no-strings-nocopy | on | | Defer record elision (panics.go) | MARMOT_DEFERELIDE | off | | Dead initializer removal (staticinit.go) | MARMOT_DEADINIT | off | | Allocation without zeroing (rtcore rt_alloc_nozero, 569d095; poison fill c8e0a15) | callers only | on | Stress modes used by the conformance runner: `gcstress` (`MARMOT_GCSTRESS=1`), `poison` (`MARMOT_POISON=1`), `lifetime` (`MARMOT_LIFETIME=all`). ## Targets [#targets] | Target | Status | Tested | | --- | --- | --- | | darwin/arm64 | primary | all tiers above | | linux/amd64 | cross compiled on macOS, run on a Linux test host | 99 of 99 conformance tests pass (tree `2c645f1`) | | linux/arm64 | not tested | | ## Tools [#tools] - `marmot build [flags] [packages or files]`: `-o`, `-O {0,1,2,3,s,z}` (default 2), `-release` (whole program, `-O3`, loop and library specializations), `-emit {mlir,llvm,obj,exe}`, `-dialect {llvm,go}`, `-gc {precise,none}`, `-target`, `-tags`, `-nocache`, `-v`, `-x`, `-work`. - `marmot run [flags] file.go [args]`: build and run. - `marmot test [-v] [-run RE] [-skip RE] [-bench RE] [-count N] [-timeout D] [packages]`: builds the `go list -test` main and runs it in the package directory. - `marmot version`. ## Known differences from gc [#known-differences-from-gc] - Panic output prints the same message and exits with status 2; the traceback below `goroutine N [running]:` is gc style but frames of inlined functions do not appear. - Floating point uses the same fused multiply-add rule as gc on arm64 (`x*y+z` fuses, an explicit conversion does not). - Variables are read after calls in the same expression, as gc does (the spec leaves this unspecified). - `runtime.Caller` and friends work from a pc table; binaries built with `-s` have none. - **NaN payloads.** Where the Go specification only says the result is a NaN, marmot may return a different NaN (payload and sign bits) than gc: the builtin `min` and `max` (also over slices, so `slices.Min` and `slices.Max`), `math.Max`, `math.Min`, and `math.Floor`, `Ceil`, `Trunc`, `Round` and `RoundToEven` of a signaling NaN (gc quiets it, marmot may return it unchanged). The value is a NaN in every case; only `math.Float64bits`, `math.Float32bits` or `unsafe` shows the difference, and gc itself differs here across architectures. Values that are not NaN are bit identical to gc on the same architecture; a difference there is a bug. Programs: `tests/run/audit/minmax_nan_payload`, `tests/run/audit/math_exp_log_bits`. - Slice growth capacities and map iteration order are not guaranteed to equal gc's. - Evaluation order: variables are read after the calls of the same expression; open cases are tracked in `tests/run/audit/evalorder_gaps`. - Unexported methods of embedded types from different packages with the same name: see `world/audit_unexported` under open failures. - cgo, the race detector, plugins, DWARF and Windows are not supported. - `reflect`: see the open failures below for the current gaps. ## Open failures [#open-failures] Listed in `tests/known_failures.txt`; a test that passes is removed from the list. - `goroot/genmeth1`: - `goroot/range4`: - `goroot/reflectmethod1`: - `goroot/reflectmethod2`: - `goroot/reflectmethod3`: - `goroot/reflectmethod4`: - `goroot/reflectmethod5`: - `goroot/reflectmethod6`: - `goroot/reflectmethod7`: - `goroot/shift3`: - `run/std/reflect/kinds_names`: - `run/opt/fma_fusion_gc`: gc fuses x*y+z on arm64, marmot does not (spec allows both) - `run/opt/panic_in_loop@Oz`: recovered panic then nil deref panic is not recoverable at -Oz - `run/std/runtime/goroutines_gc`: runtime.Caller unsupported (no pc to file:line table yet) - `run/std/log/basic`: runtime.Caller unsupported, log.Lshortfile prints ???:0 - `world/ulid`: return id, parse(&id): gc reads variables after calls (see core/eval_order_var_after_call) - `run/mem/regionstore@lifetime`: MARMOT_LIFETIME=all: region store use-after-free, expected until fixed - `world/audit_unexported`: unexported methods of different packages are confused in itabs - `run/audit/deadinit_bigmake`: huge make: fatal "out of memory" instead of the makeslice panic (dead initializer removal) - `run/audit/defer_builtin_recover`: recover() result lost for a deferred builtin - `run/audit/evalorder_gaps`: map index evaluation order differs from gc - `run/audit/fma_complex_mul`: complex multiply: fused multiply-add bits differ from gc - `run/audit/make_huge_const`: make with a huge constant length does not panic like gc - `run/audit/math_exp_log_bits`: math.Exp(-745.13) returns 0x1, gc 0x0 (value difference, not a NaN payload) - `run/audit/method_value_nil_iface`: method value of a nil interface panics with the wrong message - `run/audit/tempstring_write`: temporary string written through (no-copy conversion) # Support (/docs/support) ## Platforms [#platforms] | Platform | State | | --- | --- | | macOS on Apple Silicon | Main development platform. | | Linux on x86-64 | Works, tested with the same suites. | | Linux on arm64 | Builds. Not yet run under test. | | Windows | Not supported. | ## Language [#language] The whole language is supported, including generics, closures, `defer`, `panic` and `recover`, goroutines, channels, `select`, range over functions, and `unsafe`. Packages that import `"C"` build; see [cgo](/docs/cgo). Not supported: plugins and the race detector. ## Standard library [#standard-library] marmot compiles Go's own standard library source. Most packages work. Packages checked by the test suite include: `bufio`, `bytes`, `context`, `crypto/sha256`, `encoding/base64`, `encoding/hex`, `encoding/json`, `errors`, `flag`, `fmt`, `io`, `log`, `log/slog`, `maps`, `math`, `math/big`, `net`, `net/http`, `os`, `os/exec`, `path/filepath`, `reflect` (most of it), `regexp`, `slices`, `sort`, `strconv`, `strings`, `sync`, `sync/atomic`, `testing`, `text/template`, `time`, `unicode/utf8`. Known gaps: `reflect.MakeFunc`, and parts of `runtime` that expose Go's own scheduler internals. ## Test results [#test-results] Every test builds a program with both compilers and compares output and exit status. | Suite | Passing | Total | | --- | --- | --- | | Core language | 134 | 135 | | Garbage collection | 13 | 13 | | Goroutines and channels | 15 | 15 | | Standard library | 249 | 249 | | Memory safety | 50 | 50 | | Struct layout | 49 | 49 | | Small applications | 12 | 12 | | Programs from Go's own test suite | 106 | 108 | | Real open source modules | 34 | 34 | | All suites | 729 | 735 | The full list, feature by feature and package by package, is in the [support matrix](/docs/support-matrix). ## Known differences from Go [#known-differences-from-go] These are cases where the Go specification allows more than one behavior and marmot does not yet match what the standard Go compiler does. | Area | Difference | | --- | --- | | Evaluation order | In a few statement shapes, a variable is read before a function call in the same statement, where Go reads it after. | | NaN values | The exact bit pattern of a NaN result can differ. It is still a NaN. | | Floating point | `math.Log` can differ in the last bit for some inputs on arm64. | | Stack traces | Panic messages match Go. The stack trace that follows has a different layout. |