# Contributing to mnml
Thanks for your interest in mnml. This guide covers the workflow, conventions,
and the bits of architecture worth knowing before you change code.
## Getting started
```bash
git clone https://github.com/chris-mclennan/mnml
cd mnml
cargo build
cargo test
```
`fim-engine` (the local FIM code-completion engine) is a workspace member at
`crates/fim-engine/` — a single `cargo build` from the mnml root builds
everything. There's no external sibling checkout to keep in sync; the crate
lived in its own repo through 2026-08-10 and was vendored in with full
git-subtree history preserved.
mnml builds on stable Rust — MSRV **1.87**, edition 2024. A
[Nerd Font](https://www.nerdfonts.com/) helps when running the UI, but isn't
needed to build or test.
### Windows
Windows needs the **`x86_64-pc-windows-gnu`** toolchain, not msvc — upstream
ghostty supports `x86_64-windows-gnu` for libghostty-vt and marks msvc as not
working yet. Set it for both host and target (`rustup override set
stable-x86_64-pc-windows-gnu`); a msvc *host* would need an MSVC linker just to
build the build scripts. You also need MinGW-w64 GCC on PATH as the linker
driver, **zig 0.16.0** (`mnml-libghostty-vt-sys` source-builds libghostty-vt),
and **libclang** from an LLVM install for bindgen.
If the final link fails with `___chkstk_ms` undefined, reported as
`relocation truncated to fit: IMAGE_REL_AMD64_REL32`, link with LLD instead:
```toml
# ~/.cargo/config.toml
[target.x86_64-pc-windows-gnu]
rustflags = ["-C", "link-arg=-fuse-ld=lld"]
```
Some MinGW binutils versions open the right `libgcc.a` but never extract
`_chkstk_ms.o`, which only shows up on a binary mnml's size — a minimal one
links fine.
## The verification gate
Every change must pass, in order:
```bash
cargo fmt # format
cargo build # compile clean
cargo clippy --all-targets # warning-free — the project keeps it clean
cargo test # unit + e2e + ipc suites green
```
`cargo clippy --all-targets` being **warning-free** is a hard requirement, not a
nice-to-have. If you're working in mnml itself, the `/verify` skill in
`.claude/skills/` runs the whole gate.
## Architecture spine
A few load-bearing pieces — read [`CLAUDE.md`](CLAUDE.md) for the full design:
- **Pluggable input layer** (`src/input/`) — `Box<dyn InputHandler>` translates
key events into a closed set of `EditOp`s (interpreted by the single chokepoint
`Editor::apply`) or escalates to an `AppCommand` / a registered `Command`. The
editor, buffer, and render layers **never** branch on which handler is active.
- **`Pane` + `Layout` + the `Command` registry** are the rest of the spine.
`Pane` is the open-thing enum, `Layout` is the split tree, and `Command` is
what the palette / which-key / keybindings / plugins all hang off.
- **Adding a feature is additive** — register a `Command`, add an `EditOp` or
`Pane` variant. It should not require special-casing across layers. If you find
yourself adding `if vim { … }` outside the statusline or cursor-shape code,
step back: the design exists specifically to avoid that.
- **Headless mode** (`src/headless.rs`) and the **file-IPC channel**
(`src/ipc/`) share `App` + `ui::draw` with the terminal loop, so headless
behaviour matches the real UI — that's the substrate for `.test` E2E coverage.
- **No giant files.** `App` state is render-free and lives across
`src/app/mod.rs` + per-subsystem siblings (`src/app/{bitbucket,github,git,
lsp,ai,dap,cdp,…}.rs` — 25 files, each owning one cohesive surface).
`src/tui.rs` is only the crossterm event loop; chrome lives in `src/ui/`;
other subsystems get their own top-level dirs.
- **Cargo features.** The default build has no optional features. `aws-codebuild`
adds `Pane::CodeBuilds` + `Pane::LogTail` (AWS CodeBuild + CloudWatch log
tail, both shelling out to the `aws` CLI; no new crate deps). Gate org-specific
code in private sibling binaries rather than adding new features here.
- **Sibling tool integrations.** Standalone TUI binaries (`mnml-forge-*`,
`mnml-aws-*`, etc.) open as Pty panes via `:term <binary>`. Adding a
new integration requires no changes to mnml — write the binary as a
regular TUI and add a `[[ui.integration_icon]]` config entry pointing
at `:term <binary>`.
## Conventions
- Run `cargo fmt` and keep `cargo clippy --all-targets` warning-free before every
commit.
- Add tests for new behaviour. Pure logic gets unit tests; UI flows get a
`.test` file under `tests/e2e/`.
- Keep commits small and focused. End commit messages with a
`Co-Authored-By:` trailer when a change is co-authored.
- Match the style of the surrounding code — comment density, naming, idioms.
## Tests
- **Unit tests** — `cargo test --lib`.
- **End-to-end** — `.test` files under `tests/e2e/` run via `cargo test` and
`mnml test`. The format is a line-based DSL (`open`, `key`, `type`, `command`,
`click`, `expect screen …`) driving the real `App` against a virtual backend.
- **IPC** — `tests/ipc.rs` exercises the file-IPC wire format.
## Pull requests
1. Branch from `main`.
2. Make your change with tests; run the verification gate.
3. Open a PR describing the change and how you verified it.
4. CI runs `fmt` + `clippy -D warnings` + `test` — keep it green.
## Reporting bugs & requesting features
Use the [issue tracker](https://github.com/chris-mclennan/mnml/issues). For bugs,
include your OS, terminal, and steps to reproduce — a `.test` file that fails is
the gold standard.
## License
By contributing, you agree that your contributions will be dual licensed under
the MIT and Apache-2.0 licenses, as described in [README.md](README.md#license),
without any additional terms or conditions.