v0.2.1 · Rust core · MIT

The file tree that keeps up with your IDE.

High-performance native primitives for Electron IDEs. A Rust engine walks, watches, and searches; a typed TypeScript client freezes viewport snapshots; React renders half a million rows without breaking a sweat.

500k+ rows virtualized
<200 ms first paint, huge monorepos
8 prebuilt native targets
12.5 KB headless UI gzip

Tree state in Rust

EntryStore, walker, watcher, ignore matching, and fuzzy search run natively. JS owns expansion, selection, and scroll — never the canonical tree.

Built for Electron

UtilityProcess host, MessagePort sessions, frozen renderer mirrors. Keep the native binary off the main thread and out of the renderer.

UI that ships

Virtualized ARIA tree, soft-duotone icons (plus Material), Git decorations, commands, DnD, and a headless entry under 13 KB gzip — drop into any React 19 app.

Capabilities

Everything a serious explorer needs — nothing an IDE doesn’t.

From parallel walks and crash-resume to decoration fan-out and compact folders, mille is the filesystem layer you would otherwise re-implement for every product.

Parallel walk + gitignore

jwalk + ripgrep’s ignore crate. Symlink-aware matching skips pnpm store links so monorepo walks stay O(tracked files), not O(store).

Watcher that stays calm

notify + 75 ms debounce, rename pairing, volatile-subtree throttling, mutation intent cache so your own edits don’t echo back as storms.

Viewport-virtualized mirror

Immutable MirrorSnapshot with stable identity. React concurrent-safe. Bulk bincode path for large viewports.

Lazy list-on-expand

initialWalk: 'roots-only' paints huge repos in under 200 ms. Children stream when folders expand — no populate-before-ready workaround.

Decorations pipeline

Git, lint, problems, agent-rules — separate decorationVersion so SCM churn never thrash tree caches. Port-side fan-out to every session.

Fuzzy filename search

nucleo-powered ranking over the in-memory tree with match indices for highlighting. Content search reserved as a companion package.

Crash-resume

Atomic bincode snapshots with parent fsync. Boot from disk, emit events_since diffs, rejoin reality without a cold full walk.

Compact folders

Single-child chains collapse to src/components/ui one-row paths — the IDE pattern users already expect.

Architecture

Four layers. One contract.

Engine logic never leaks into NAPI. View state never lives in Rust. The host/client split keeps native code where Electron expects it.

UI

React file tree

ARIA tree, virtualization, keyboard, rename, DnD, icons, Git badges. Styled or headless.

@vibecook/mille-ui
Client

Typed mirror + port protocol

FileExplorer wrapper, ViewportMirror, deltas, decorations store, React snapshot hook, MessagePort client.

@vibecook/mille
Binding

NAPI surface

Marshal-only cdylib. Prebuilt .node binaries for eight platform triples via optionalDependencies.

mille-binding · mille-{triple}
Core

Pure Rust engine

EntryStore, walker, watcher, ignore, search, resume. Unit-testable without Node. Bindable beyond NAPI later.

mille-core

Packages

Engine and UI, designed to ship together.

Use the engine alone for custom surfaces, or take the full tree UI and be productive in an evening.

@vibecook/mille

Explorer engine

Native core + TypeScript client for Node and Electron UtilityProcess hosts.

  • In-process FileExplorer
  • createFileExplorerHost / connectFileExplorer
  • Decorations providers
  • useFileExplorerSnapshot
@vibecook/mille-ui

React companion

Drop-in FileTree with VS Code icon theme compatibility and IDE-grade interactions.

  • WAI-ARIA 1.2 tree pattern
  • Git + agent-rules decorations
  • Soft-duotone + Material icon themes
  • Headless entry · testing fakes

Quickstart

From install to first snapshot in minutes.

Absolute roots only. Construction is cheap — call populateFromRoots() when you want I/O.

install
# engine + UI
pnpm add @vibecook/mille @vibecook/mille-ui

# peers for the styled tree
pnpm add react react-dom @tanstack/react-virtual
node · minimum viable
import { FileExplorer } from '@vibecook/mille';

const fx = new FileExplorer({
  roots: ['/path/to/workspace'],
});
await fx.populateFromRoots();

const snap = fx.getSnapshot();
for (const root of snap.roots()) {
  console.log(root.id, root.name);
}
await fx.dispose();
react · FileTree
import { FileExplorer } from '@vibecook/mille';
import { FileTree } from '@vibecook/mille-ui';
import '@vibecook/mille-ui/tokens.css';

const fx = new FileExplorer({ roots: ['/path/to/workspace'] });
await fx.populateFromRoots();

export function Sidebar() {
  return <FileTree fx={fx} ariaLabel="Files" rowHeight={22} />;
}

Electron

Native binary stays in UtilityProcess.

Main forks the host. Each window gets a MessagePort. The renderer never loads .node.

Main Forks utility, creates MessageChannel, wires ports
UtilityProcess createFileExplorerHost · walker · watcher · .node
Renderer connectFileExplorer(port) · FileTree · mirror

Full main / host / preload / renderer walkthrough lives in the package embedding guide. See EMBEDDING.md and the playground app under apps/playground.

Platforms

Prebuilt natives. Install once.

The umbrella package resolves the correct binary through optionalDependencies — no postinstall compile step for supported targets.

Platform Package
macOS arm64@vibecook/mille-darwin-arm64
macOS x64@vibecook/mille-darwin-x64
Windows x64@vibecook/mille-win32-x64-msvc
Windows arm64@vibecook/mille-win32-arm64-msvc
Linux x64 glibc@vibecook/mille-linux-x64-gnu
Linux arm64 glibc@vibecook/mille-linux-arm64-gnu
Linux x64 musl@vibecook/mille-linux-x64-musl
Linux arm64 musl@vibecook/mille-linux-arm64-musl

Ship an explorer that feels native.

Open the API, clone the playground, or drop mille into your Electron shell tonight.