A modern, desktop IDE for the Unison programming language built with Tauri 2, React 19, and Monaco Editor.
Pre-built installers for macOS and Linux are available at:
https://kingsleyh.github.io/unison-editor/
- Monaco Editor with Unison syntax highlighting and dark theme
- Tab-based editing with multiple files open simultaneously
- File Explorer with drag-and-drop, multi-select, and context menus
- Workspace persistence - tabs, layout, and window state restored on reopen
- Integrated UCM Terminal - Full PTY-based terminal with xterm.js
- Automatic UCM lifecycle management - UCM spawns automatically when opening a workspace
- Project & Branch switching - Switch between Unison projects and branches
- Namespace Browser - Tree view for exploring the codebase with lazy loading
- Hover information - Type signatures and documentation on hover
- Autocomplete - Intelligent completions from the codebase
- Go-to-definition - Click-through navigation to definitions
- Definition Cards - UCM Desktop-style stacked definition viewer
- Syntax help - Built-in help for Unison keywords and operators
- Real-time diagnostics - Errors and warnings from UCM's LSP server
- WebSocket proxy - Bridges the frontend to UCM's LSP server
- Watch expressions - Lines starting with
>can be evaluated - Test runner - Run tests defined with
test>expressions - Run pane - Displays evaluation results with syntax highlighting
- Create/rename/delete files and folders
- Unison file support (
.uextension) - Scratch files for quick experiments
- Rust (1.77.2 or later) - Install Rust
- Node.js (v18 or later) - Install Node.js
- UCM (Unison Codebase Manager) - Install Unison
UCM is typically installed via Homebrew:
brew install unisonweb/unison/unisonnpm installnpm run tauri devThis starts the Vite dev server and launches the Tauri app with hot module replacement.
npm run tauri buildCreates platform-specific bundles:
- macOS:
.dmgand.appinsrc-tauri/target/release/bundle/ - Linux:
.AppImageinsrc-tauri/target/release/bundle/
- Launch the app - you'll see the Welcome Screen
- Click "Open Folder" to select a workspace directory
- UCM starts automatically and connects to the codebase
- If no Unison codebase exists, you can create one or link to an existing project
- Left Sidebar: File Explorer and Namespace Browser
- Center: Editor tabs with Monaco editor
- Right Panel: Definition Stack (collapsible)
- Bottom Panel: UCM Terminal, Output, and General Terminal (collapsible)
- Browse the namespace tree to explore definitions
- Click a definition to open it in the Definition Stack
- Click "Add to Scratch" to copy source code to a scratch file
- Use the search box in the Namespace Browser to find definitions
In any .u file, prefix a line with > to create a watch expression:
> 1 + 1
> List.map (x -> x * 2) [1, 2, 3]
Click the play button in the gutter to evaluate.
Define tests with the test> prefix:
test> myTest = check (1 + 1 == 2)
unison-editor/
├── src/ # React frontend
│ ├── components/ # React components
│ │ ├── Editor.tsx # Monaco editor wrapper
│ │ ├── UCMTerminal.tsx # Integrated UCM terminal
│ │ ├── NamespaceBrowser.tsx # Codebase tree browser
│ │ ├── FileExplorer.tsx # Workspace file browser
│ │ ├── DefinitionStack.tsx # Definition cards viewer
│ │ └── ...
│ ├── services/ # Business logic
│ │ ├── ucmApi.ts # UCM HTTP API client
│ │ ├── lspService.ts # LSP client
│ │ ├── ucmLifecycle.ts # UCM process management
│ │ └── monacoUcmProviders.ts # Hover/completion providers
│ ├── editor/ # Editor configuration
│ │ └── unisonLanguage.ts # Syntax highlighting
│ ├── store/ # State management
│ │ └── unisonStore.ts # Zustand store
│ └── theme/ # Theming
│ └── unisonTheme.ts # Dark theme config
├── src-tauri/ # Rust backend
│ └── src/
│ ├── lib.rs # Tauri app setup
│ ├── commands.rs # Tauri commands
│ ├── ucm_api.rs # UCM HTTP API client
│ ├── ucm_pty.rs # PTY management for UCM
│ ├── lsp_proxy.rs # LSP WebSocket proxy
│ └── port_utils.rs # Port allocation
├── package.json
└── README.md
┌─────────────────────────────────────────────────────────────┐
│ Tauri Desktop App │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ React Frontend (Vite + TypeScript) │ │
│ │ • Monaco Editor with Unison syntax │ │
│ │ • xterm.js for UCM terminal │ │
│ │ • Zustand for state management │ │
│ └───────────────────────────────────────────────────────┘ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ Rust Backend (Tauri 2) │ │
│ │ • UCM PTY management (portable-pty) │ │
│ │ • HTTP client for UCM API (reqwest) │ │
│ │ • LSP WebSocket proxy (tokio-tungstenite) │ │
│ │ • File system operations │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌───────────────────────────────┐
│ UCM (spawned by app) │
│ • HTTP API (dynamic port) │
│ • LSP Server (port 5757) │
│ • SQLite Codebase │
└───────────────────────────────┘
# Frontend tests
npm test # Watch mode
npm run test:run # Single run
# Rust tests
cd src-tauri
cargo test# Check TypeScript
npx tsc --noEmit
# Check Rust
cd src-tauri && cargo checkEach workspace stores its configuration in .unison-editor/:
config.json- Linked project, default brancheditor-state.json- Open tabs, layout, window state
UCM services use dynamic port allocation:
- UCM API: Starting at 5858
- LSP Server: Fixed at 5757 (UCM limitation)
- LSP WebSocket Proxy: Starting at 5758
If you see "UCM Not Found" when opening a workspace:
- Ensure UCM is installed:
which ucm - If installed via Homebrew, ensure
/opt/homebrew/binis in your PATH - The app automatically adds common paths, but custom installations may need manual configuration
If you see "UCM Already Running":
- Another UCM instance is using the same codebase
- Close the other UCM instance (terminal, other editor) and click Retry
- Check the UCM Terminal panel for error messages
- Verify UCM started successfully
- Try closing and reopening the workspace
- React 19 with TypeScript
- Zustand for state management
- Monaco Editor for code editing
- xterm.js for terminal emulation
- Vite 7 for bundling
- Tauri 2 for desktop app framework
- portable-pty for PTY management
- reqwest for HTTP requests
- tokio for async runtime
- tokio-tungstenite for WebSocket proxy
MIT
- Built with inspiration from the Unison team's UCM Desktop
- Syntax highlighting adapted from Unison language definitions
- Icons from the Unison project