|
| 1 | +# Architecture |
| 2 | + |
| 3 | +``` |
| 4 | +┌──────────────────────────────────────────────────────────┐ |
| 5 | +│ TypeScript layer — 6 packages │ |
| 6 | +│ @mlx-node/lm Inference, ChatSession, streaming │ |
| 7 | +│ @mlx-node/trl GRPO/SFT training, datasets │ |
| 8 | +│ @mlx-node/vlm VLM, OCR, document pipelines │ |
| 9 | +│ @mlx-node/server HTTP server (/v1/responses, /v1/messages)│ |
| 10 | +│ @mlx-node/cli mlx download, mlx convert, mlx launch │ |
| 11 | +│ @mlx-node/core Native addon (NAPI bindings) │ |
| 12 | +├──────────────────────────────────────────────────────────┤ |
| 13 | +│ Rust compute layer — 5 workspace crates │ |
| 14 | +│ mlx-core Models, training, ops, vision (all NAPI) │ |
| 15 | +│ mlx-paged-attn PagedAttention + Metal kernels │ |
| 16 | +│ mlx-sys Low-level MLX FFI bridge (cpp + headers) │ |
| 17 | +│ mlx-db SQLite training persistence │ |
| 18 | +│ mlx-tui mlx-train Ratatui binary (no library deps)│ |
| 19 | +├──────────────────────────────────────────────────────────┤ |
| 20 | +│ C++ bridge → Compiled forward paths │ |
| 21 | +│ ~300 FFI declarations, compiled decode via mlx::compile │ |
| 22 | +├──────────────────────────────────────────────────────────┤ |
| 23 | +│ MLX → Metal / Accelerate GPU backend │ |
| 24 | +└──────────────────────────────────────────────────────────┘ |
| 25 | +``` |
| 26 | + |
| 27 | +## Package dependency chain |
| 28 | + |
| 29 | +``` |
| 30 | +@mlx-node/core (Rust/NAPI native addon) |
| 31 | + ├── @mlx-node/lm inference, models, streaming, tools, profiling |
| 32 | + │ ├── @mlx-node/trl training (GRPO, SFT, datasets, rewards) |
| 33 | + │ ├── @mlx-node/vlm vision (VLM, OCR, document pipeline) |
| 34 | + │ └── @mlx-node/server HTTP server (SessionRegistry, /v1/* endpoints) |
| 35 | + └── @mlx-node/cli depends on core + lm + server |
| 36 | +``` |
| 37 | + |
| 38 | +`mlx-tui` is the workspace binary crate (Ratatui-based `mlx-train` TUI) — it's a workspace member but no other crate depends on it, so it's built separately via `cargo build -p mlx-tui`. `@mlx-node/internal-tools` lives in root `devDependencies` and is not part of the runtime chain. |
| 39 | + |
| 40 | +## Repository layout |
| 41 | + |
| 42 | +``` |
| 43 | +mlx-node/ |
| 44 | +├── Cargo.toml workspace manifest (5 crates) |
| 45 | +├── package.json npm workspaces (6 packages + examples) |
| 46 | +├── vite.config.ts Vitest + Oxlint + Oxfmt config |
| 47 | +├── tsconfig.json TypeScript project references |
| 48 | +│ |
| 49 | +├── crates/ |
| 50 | +│ ├── mlx-sys/ MLX C/C++ FFI bridge — see ffi-cpp.md |
| 51 | +│ ├── mlx-core/ All NAPI exports: models, training, ops, vision |
| 52 | +│ ├── mlx-paged-attn/ PagedAttention + Metal shaders — see paged-cache.md |
| 53 | +│ ├── mlx-db/ SQLite training persistence |
| 54 | +│ └── mlx-tui/ mlx-train Ratatui binary (standalone) |
| 55 | +│ |
| 56 | +├── packages/ |
| 57 | +│ ├── core/ @mlx-node/core (native addon + .d.cts) |
| 58 | +│ ├── lm/ @mlx-node/lm |
| 59 | +│ │ └── src/ |
| 60 | +│ │ ├── chat-session.ts ChatSession<M> cross-model wrapper |
| 61 | +│ │ ├── stream.ts Session-aware models + callback→AsyncGenerator bridge |
| 62 | +│ │ ├── profiling.ts JS profiling API |
| 63 | +│ │ ├── models/ loadModel, loadSession, configs |
| 64 | +│ │ └── tools/ Tool definition types |
| 65 | +│ ├── trl/ @mlx-node/trl (trainers/, data/, utils/) |
| 66 | +│ ├── vlm/ @mlx-node/vlm (models/, pipeline/) |
| 67 | +│ ├── server/ @mlx-node/server |
| 68 | +│ │ └── src/ |
| 69 | +│ │ ├── endpoints/ /v1/responses, /v1/messages |
| 70 | +│ │ └── session-registry.ts SessionRegistry — owns ChatSession lifetimes |
| 71 | +│ └── cli/ @mlx-node/cli — see cli.md |
| 72 | +│ |
| 73 | +├── __test__/ TypeScript tests |
| 74 | +└── examples/ lm.ts, vlm-inference.ts, paddle-ocr-pipeline.ts, tool-use-example.ts, grpo/, sft/ |
| 75 | +``` |
| 76 | + |
| 77 | +## Build flow |
| 78 | + |
| 79 | +| Command | Output | |
| 80 | +| ---------------------------------- | ---------------------------------------------------------------------------------------------- | |
| 81 | +| `yarn build` | `yarn build:native && yarn build:ts` | |
| 82 | +| `yarn build:native` | `packages/core/index.cjs`, `mlx-core.darwin-arm64.node`, `mlx.metallib`, `paged_attn.metallib` | |
| 83 | +| `yarn build:ts` | `packages/*/dist/` via `tsc -b` (project references) | |
| 84 | +| `yarn typecheck` | TypeScript type-check only | |
| 85 | +| `cargo build --release -p mlx-tui` | `mlx-train` TUI binary | |
| 86 | + |
| 87 | +`yarn build:native` is the **canonical native build** — runs the napi-rs pipeline through `packages/core/build.ts` (executed via `oxnode`). Running `cargo build` directly does **not** produce the `.node` addon. |
| 88 | + |
| 89 | +## Adding a new native operation |
| 90 | + |
| 91 | +1. Add FFI declaration in `crates/mlx-sys/src/lib.rs`. |
| 92 | +2. Add C++ bridge function in the appropriate `crates/mlx-sys/src/mlx_*.cpp` file (see [ffi-cpp.md](ffi-cpp.md) for which file owns what). |
| 93 | +3. Add a Rust wrapper in `crates/mlx-core/src/` with `#[napi]` exports. |
| 94 | +4. Run `yarn build:native` to regenerate NAPI bindings and `packages/core/index.d.cts`. |
| 95 | +5. Add tests using TypedArray helpers. |
| 96 | + |
| 97 | +If you added a **new** `.cpp` file, run `rm -rf target/release/build/mlx-sys-*` once — the `cc` crate caches the source-file list across builds and won't pick up new files otherwise. |
| 98 | + |
| 99 | +## Adding a TypeScript utility |
| 100 | + |
| 101 | +1. Pick the package by responsibility: `lm` (inference), `trl` (training), `vlm` (vision), `server` (HTTP), `cli` (CLI). |
| 102 | +2. Add to `packages/<pkg>/src/`, export from `packages/<pkg>/src/index.ts`. |
| 103 | +3. Run `yarn build:ts && yarn typecheck`. |
0 commit comments