ashlar
A lightweight, modern application framework for Rust, powered by egui.
ashlar gives a desktop (and, for its headless core, web) application the parts every app rebuilds: documents with undo and autosave; commands that drive menus, shortcuts, a command palette, a CLI and an MCP server; background jobs; files and settings; native OS features; a component library on egui; and crash safety and telemetry. An idle ashlar app does no work at all.
Status: early (0.1). The API will change between minor versions until 1.0.
Why ashlar
- Everything is a command. Menus, shortcuts, the palette, the CLI, the control port and MCP all go through one registry and one execute chokepoint, so anything a user can do, a script or an AI agent can do too.
- Never crashes. No
unwrap,panic!orunsafeoutside tests (enforced by lints and a CI gate). Panics in a view, a command or a job are caught; the session survives and unsaved work is recovered on the next launch. - Zero work when idle. Frames are drawn only when something asks for one: input, a document change, a finished job, a running animation. No polling. A focused text field stops its caret after 10 s, and a settled animation asks for nothing.
- Fast where it matters. It scrolls a 1,000-row list in 0.10 ms of CPU per frame with
list::Row, and a virtualized list in 0.035 ms whatever its length. It draws a static 52 KB markdown document in 0.03 ms. Allocations per frame and frame time are gated in CI. The numbers, the method and a comparison with another native Rust UI framework are in docs/benchmarks.md. - Built for agents. Every app takes
--headless --snap out.png --tree tree.json(real pixels, no window)..uiscripts run in process on a virtual clock, andapp.clockpauses and steps time. Golden screenshots, named scenes, a motion and jank gate, and record and replay come with it. - Motion and accessibility. Animations use springs that keep their velocity when retargeted, and follow the OS reduced-motion, accent and contrast settings. Every component reports AccessKit roles and states, and the gallery's accessibility trees are golden-tested.
- Headless core. Documents, commands, jobs and files never touch the UI, so they run in tests, in a CLI, behind MCP and in the browser.
- Small crates. Use the umbrella crate, or pick only the layers you need: each
ashlar-*crate works on its own.
Quick start
The package is published as ashlar-rs; the library is still imported as ashlar.
use *;
App::cli() turns the same definition into a -cli binary with commands, exec, run, mcp
and serve. --control <port> lets an agent drive the window. Try the examples:
The umbrella crate's features:
| Feature | Default | What it adds |
|---|---|---|
accesskit |
on | Screen readers and other assistive technology see the window (AccessKit) |
headless |
on | --headless on the app's command line: no window, .ui scripts, --snap, --tree |
native-menu |
off | The app's commands in the macOS and Windows menu bar |
tray |
off | A tray or status-bar icon with a menu (App::tray) |
hotkey |
off | System-wide shortcuts (App::global_shortcut) |
telemetry |
off | Crash, performance and usage reports to a server you host |
Binary size: the smallest app (examples/hello) is 13.6 MB stripped in a release build on macOS
arm64. cargo build --profile release-small (a profile in this workspace: fat LTO, one codegen
unit, opt-level = "s", stripped) brings it to 9.0 MB; copy the profile into your own
Cargo.toml. default-features = false saves about 1 MB more, at the cost of accessibility and
--headless. cargo xtask bench tracks the number as hello_stripped_bytes.
Crates
Every crate is published on crates.io under the same
version, with its API docs at https://docs.rs/<crate>. Depend on a single layer when that's all
you need, for example cargo add ashlar-store for documents and undo in a headless tool.
| Crate | What it is |
|---|---|
ashlar-rs |
The umbrella crate (use ashlar::…): re-exports the layers below behind features |
ashlar-app |
The runtime: App builder, frame scheduler, crash guard, logging, agent control |
ashlar-ui |
UI components on egui: OKLCH theme tokens, motion, controls, overlays, tabs, forms, lists and trees, markdown, code and diff views, a chat kit, docking |
ashlar-motion |
Springs, tweens and decay that keep velocity when retargeted; OKLab colour; reduced-motion rules (headless, wasm32) |
ashlar-syntax |
Syntax highlighting for 18 languages, incremental and linear-time (headless, wasm32) |
ashlar-diff |
Myers diffs with word-level emphasis, and a unified-patch reader and writer (headless, wasm32) |
ashlar-store |
Documents: Arc snapshots, revisions, undo history, versioned formats, autosave |
ashlar-command |
Commands: registry, typed params, one execute chokepoint, discovery |
ashlar-jobs |
Background jobs: progress, cancel, panic isolation, apply on the UI thread |
ashlar-fs |
Files and settings: app folders, atomic writes, keyed settings, recent files |
ashlar-log |
Logging and crash safety: filters, rotating file, in-memory ring, panic hook |
ashlar-native |
OS features behind one API: dialogs, menus, clipboard, power, notifications, secrets |
ashlar-control |
The agent control port: a hardened JSON-lines server and client |
ashlar-cli |
Standard CLI verbs over the command registry |
ashlar-mcp, ashlar-mcp-http |
An MCP server generated from the command registry (stdio, or HTTP on loopback) |
ashlar-agents |
Connect coding agents to an app: MCP config, skills and rules |
ashlar-assistant |
An in-app AI assistant harness, independent of the model provider |
ashlar-integrations |
Code-signed tool servers installed from a catalog and run over MCP |
ashlar-debug |
Drive a running app's UI from the shell: snapshot, click, wait, screenshot |
ashlar-docs |
Documentation for agents, embedded at build time |
ashlar-update |
Update checks against a releases API |
ashlar-print |
Send a PDF to the system print spooler (CUPS, Windows) |
ashlar-i18n |
Translations: JSON catalogs, plural rules, number formatting, locale negotiation |
ashlar-obfuscate |
Compile-time string obfuscation |
ashlar-telemetry, ashlar-trace, ashlar-trace-server, ashlar-trace-proto |
Self-hosted crash, performance and usage telemetry (docs) |
How the crates stack is in docs/architecture.md.
Compatibility
| Supported | |
|---|---|
| Rust | 1.95 or newer (edition 2024). CI tests on the latest stable and checks the MSRV. |
| egui / eframe | 0.36, wgpu renderer |
| macOS | Apple silicon and Intel (CI: macos-latest, arm64) |
| Windows | 10 or newer, x86_64 (CI: windows-latest) |
| Linux | x86_64, X11 and Wayland (CI: ubuntu-latest). Native dialogs use the XDG desktop portal. |
| Web | wasm32-unknown-unknown for the headless core (commands, store, files, jobs, logging; checked in CI). The windowed runtime on the web is experimental: examples/web-hello builds in the gate, and App::canvas_id picks the canvas; a start failure shows a visible error next to it. |
Linux build dependencies (Debian/Ubuntu names):
Native features differ by platform. Where one isn't available, the call returns
NativeError::Unsupported and nothing panics. Some highlights (the full matrix is in
crates/native):
| Feature | macOS | Windows | Linux | Web |
|---|---|---|---|---|
| File dialogs | yes | yes | yes (portal) | open only |
| Native menu bar | yes | yes | in-window menu | in-window menu |
| Clipboard (text, image) | yes | yes | yes | no |
| Notifications | bundled apps | no | yes (D-Bus) | no |
| Secrets (OS keychain) | Keychain | Credential Manager | Secret Service | no |
| Printing | CUPS | Windows spooler | CUPS | no |
Built on egui, eframe, wgpu, rfd, muda and rustls.
Built with ashlar
- bay and bay-effects by Marl Studio are built on top of ashlar.
Building something with ashlar? Open a pull request to add it here.
Documentation
The guide, developer docs and changelog are at ashlar.himanshuat.com (llms-full.txt for AI agents).
- Architecture: crate ranks, design principles, the performance gate
- Benchmarks: how fast ashlar is, how it is measured, and a head-to-head comparison
- Control protocol: driving an app from scripts and agents
- Debugging UIs with
ashlar-debug - Telemetry: integration, privacy, self-hosting, wire format
- UI: docking, visual regression tests
- API reference on docs.rs
Contributing
Contributions are welcome. Read CONTRIBUTING.md first. Every change must pass
cargo xtask ci. Please follow the Code of Conduct, and report security
issues privately as described in SECURITY.md.
License
ashlar is licensed under the BSD 3-Clause License. Unless you say otherwise, any contribution you submit for inclusion in ashlar is licensed the same way.