Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Architecture

ashlar is a workspace of small crates stacked in ranks. An app depends on the umbrella crate ashlar-rs (imported as ashlar) and turns on the features it needs; each layer below it can also be used on its own.

Crate ranks

A crate depends only on crates of a lower rank (dev-dependencies are exempt). Ranks 0–4 never depend on a UI crate (egui, eframe, winit, egui-wgpu, egui_kittest), and ranks 0–1 build for wasm32-unknown-unknown, as do ashlar-ui and ashlar-app (the web build path). cargo xtask layers and cargo xtask wasm enforce this; the table below must match LAYERS in xtask/src/main.rs (a crate missing from LAYERS fails the gate).

RankCrateWhat it isHeadlesswasm32
0ashlar-commandCommands: registry, typed params, one execute chokepoint, discoveryyesyes
0ashlar-fsFiles and settings: app dirs, durable atomic writes, keyed settings, recent filesyesyes
0ashlar-jobsBackground jobs: progress, cancel, panic isolation, apply-on-UI-threadyesyes
0ashlar-trace-protoTelemetry wire format: envelopes, items, name rules, limitsyesyes
0ashlar-docsDocumentation library for agents: folders are categories, markdown files are documents, embedded at build time, a run-time folder on topyesyes
0ashlar-logLogging and crash safety: directive filters, stderr + rotating file + ring, panic hook, launch guardyesyes
0ashlar-obfuscateCompile-time string obfuscation: build-time values kept out of a strings dump of the binaryyesyes
0ashlar-motionMotion maths: closed-form springs, curves, animated values that keep their velocity on retarget, reduced-motion rules per value class, motion tokens, OKLab/OKLCH colour, gesture helpersyesyes
0ashlar-syntaxSyntax highlighting: linear-time lexers for 18 languages, line states for incremental views, a Highlighter trait for bigger enginesyesyes
0ashlar-diffText diffs: Myers with a cost cap, word-level changes, hunks with collapsible context, a unified-patch parser and writeryesyes
0ashlar-i18nTranslations: JSON catalogs per locale with fallback chains, {name} templates, CLDR plural categories, number formatting, locale negotiation and catalog checksyesyes
1ashlar-traceTelemetry SDK: consent, spool, sending, crash/hang/frame/system signals, event catalogyesyes (no-op)
1ashlar-storeDocuments: Arc snapshots, revisions, undo history, versioned formats, autosaveyesyes
2ashlar-nativeNative OS features behind one API: dialogs, menus, clipboard, power, notifications, secretsyes–
2ashlar-controlAgent control port: hardened JSON-lines server, client, standard method setyes–
2ashlar-trace-serverSelf-hosted telemetry server: ingest, SQLite store, rollups, dashboardyes–
2ashlar-printSystem PDF print spooler (CUPS, Windows)yes–
2ashlar-updateUpdate checks: latest release from a releases API, semver comparison, background schedule, cached result, “later” per versionyes–
2ashlar-integrationsIntegrations: tool servers installed from a catalog (download with resume and sha256, code-signature check, versions, enable/disable) and run as MCP servers over stdio; their tools for an assistantyes–
2ashlar-mcp-httpMCP over streamable HTTP on loopback for an open app: bearer token, Host/Origin checks, a gate, sessionsyes–
2ashlar-agentsConnect coding agents to an app: its MCP server in each agent’s config, skills and rules from a docs category, install and uninstallyes–
3ashlar-telemetryAlways-on crash, performance and usage telemetry over ashlar-trace: client, transport, hooks for commands, logs, frames and dialogsyes–
3ashlar-mcpMCP server generated from the command registry (stdio), headless or bridgedyes–
4ashlar-cliStandard CLI verbs over the command registryyes–
4ashlar-assistantIn-app AI assistant harness, independent of the model: conversation and tool types, providers (an account backend, Anthropic, OpenAI-compatible), the agent loop with approvals, keys in the OS keychain, an MCP server as the tool hostyes–
4ashlar-debugashlar-debug: drive a running app’s UI from the shell (snapshot, refs, click, wait, screenshot, scripted UI tests)yes–
5ashlar-uiUI components on egui: theme tokens, controls, layout, docking, iconsnoyes
6ashlar-appRuntime: App builder, frame scheduler, crash guard, logging, telemetry, agent controlnoyes
7ashlar-rsUmbrella crate (imported as ashlar): re-exports the others behind featuresno–
8ashlar-example-gallery, ashlar-example-hello, ashlar-example-notes, ashlar-example-trace-demo-cli, ashlar-example-trace-loadgen, ashlar-example-web-helloExample appsno–
9xtaskRepo gates and tools (cargo xtask …)––

Adding a crate: give it the lowest rank its dependencies allow, add it to LAYERS and to this table, add [lints] workspace = true to its manifest, and add it to [workspace.dependencies] with both path and version.

Design principles

  1. Never crash. No unwrap/expect/panic!/unreachable!/todo!/unimplemented! and no unsafe outside tests. Every input-derived number is hostile: get() instead of indexing, checked or saturating math, capped allocations, bounded recursion. Lock poisoning is not fatal. Background work runs under catch_unwind. Enforced by the workspace clippy lints and cargo xtask deny-panics.
  2. No app code, no app names. A crate here serves more than one app and never depends on one. App-specific widgets (a timeline, a CAD canvas) stay in the apps and are built from ashlar’s primitives. Docs say “a video editor”, “a DAW”. Enforced by cargo xtask names.
  3. A 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. The UI is openly egui; there is no renderer-agnostic abstraction.
  4. Everything is a command. Menus, shortcuts, the palette, the CLI and MCP all go through one registry and one execute chokepoint, so anything a user can do an agent can do.
  5. Performance is a feature. Idle apps do zero work (repaint on demand). Caches are keyed by revision numbers, not by diffing. Long lists are virtualized. No blocking I/O on the UI thread. Edits are copy-on-write with structural sharing. Every hot path has a perf test, and cargo xtask bench --compare guards it (see below).
  6. Motion is a policy. Nothing animates on first show, the user’s own hand is never animated, reduced motion is applied per value class (ashlar-motion’s Class), and settled animations request no frames.
  7. Stable contracts. Items marked CONTRACT in ashlar-command are shared across crates built in parallel and change only additively.

Performance gate

Hot paths have perf tests: #[test] #[ignore] functions whose names start with perf, usually in tests/perf.rs. They print their numbers as

bench: <metric> <value> <unit>        e.g. bench: edit_100k 812 ns

Units ending in /s are higher-is-better; all others lower-is-better. A test that prints no bench: line is measured by wall time, which is noisy, so prefer explicit metrics.

One step is not a test: perf_hello_size builds examples/hello (an empty document, a heading and a checkbox) in release, strips a copy and reports hello_stripped_bytes, the size the framework adds to every app. cargo build --profile release-small (fat LTO, one codegen unit, opt-level = "s", stripped) is the workspace’s size profile.

cargo xtask bench                             # writes target/bench/bench.{json,md}
cp target/bench/bench.json baseline.json      # before a change
cargo xtask bench --repeat 3 --compare baseline.json   # fails on a >5% regression

--repeat N keeps the best value of each metric over N rounds; --threshold PCT changes the 5%; --filter TEXT runs only matching tests.

Dependencies

cargo xtask ci checks duplicate versions and sources of every dependency when cargo-deny is installed (deny.toml); cargo xtask advisories also checks the advisory database.