Elyra
Elyra The coding agent e The native code editor Elyra Grove Native local development environment Askr The real server for Laravel & PHP Elyra Framework Rust + Svelte 5 framework for desktop apps Elyra Conductor Local project conductor Elyra SQL Server MySQL-compatible SQL server in Rust Elyra Félagi Agents as teammates on one board Elyra SQL Client Native desktop SQL workbench Elyra SQL Anywhere Replication-ready SQL engine Elyra Sjá SEO & GEO workspace for macOS Elyra DataGrid Server-driven data grid for Laravel
Release notes
Changelog
Elyra

Getting started

Prerequisites

  • Rust (stable, 1.94+) and Cargo — the floor comes from sqlx 0.9.

  • Node.js 20.19+ or 22.12+ (Vite 8's floor) and npm — for the Svelte frontend.

  • macOS is the primary target today (tao/wry use system WebKit). Linux and Windows compile and are covered by CI, but are less exercised in practice.

  • Linux build dependencies: WebKitGTK, GTK 3, and libxdo (the last one for the application menu). On Debian/Ubuntu:

    sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libxdo-dev libssl-dev pkg-config
    # plus libayatana-appindicator3-dev for the `tray` feature
    # and libdbus-1-dev for `system` (notifications)
    

Scaffold a project

rata new myapp                 # or: rata new myapp --elyra ./path/to/framework
cd myapp

This generates a self-contained workspace:

myapp/
├── Cargo.toml          # bin crate `myapp`, its own [workspace]
├── elyra.toml          # Ratatosk project descriptor
├── src/main.rs         # commands + App
└── app/                # Vite + Svelte 5 frontend
    ├── package.json
    ├── vite.config.js
    ├── index.html
    └── src/
        ├── main.js
        ├── App.svelte
        ├── app.css     # default theme (Tokyo Night palette)
        └── theme.js    # auto / light / dark switching

Default theme

New projects ship a default theme — the Tokyo Night palette (the same colors as Grove / Elyra Conductor), as CSS variables in app.css. It's dark by default, with a light variant via [data-theme="light"], and theme.js provides auto / light / dark switching (persisted to localStorage; auto follows the OS). The starter App.svelte includes a theme toggle — edit app.css to make it your own.

By default the generated project depends on the matching tagged GitHub releaseelyra = { git = "…", tag = "v0.5.7" } for Rust, and the @elyra/runtime tarball attached to that release for the frontend. Elyra isn't published to crates.io or npm; see releasing.

--elyra <path> instead points the generated Cargo.toml at a local checkout and wires @elyra/runtime to its sibling runtime/ via a file: dependency, so both cargo and npm install work offline. Use it when developing the framework itself.

Run it

cd app && npm install && npm run build && cd ..   # build the frontend once
rata codegen                                       # generate typed bindings
cargo run                                          # launch the window

Or during development, with Vite HMR:

rata dev

The Rust binary embeds the built frontend (rust-embed) and serves it from memory over the elyra://localhost custom protocol, with an ETag per asset so reloads are cheap. Before you've built the frontend, the shell serves a built-in fallback page so cargo run works alone.

Everything under elyra://localhost/__* (commands, events, the facades) is gated by a per-run IPC token that the shell injects into the webview. @elyra/runtime attaches it for you — if you hand-roll a fetch, read security first.

A first command

src/main.rs:

use elyra::{command, commands, App, Ctx};

#[command]
async fn greet(_ctx: Ctx, name: String) -> String {
    format!("Hello, {name}!")
}

fn main() -> elyra::Result<()> {
    App::new()
        .title("myapp")
        .commands(commands![greet])
        .assets(elyra::asset_resolver::<Assets>())
        .run()
}

Frontend (app/src/App.svelte):

<script>
  import { invoke } from "@elyra/runtime";
  let name = $state("world");
  let out = $state("");
</script>
<input bind:value={name} />
<button onclick={async () => (out = await invoke("greet", name))}>greet</button>
<p>{out}</p>

After rata codegen you also get a typed facade:

import { api } from "./bindings";
const out = await api.greet(name); // (name: string) => Promise<string>

Next