originv0.2.0

CASOON Open Source

Desktop apps that stop reinventing the platform.

Origin is a reference architecture and starter system for modular desktop applications in Rust and Tauri: architecture rules, reusable platform crates, security conventions and build processes, plus a reference application that demonstrates all of it.

cargo add origin-app origin-tauri
pnpm add @casoon/origin-client @casoon/origin-ui
git clone https://github.com/casoon/origin
MITv0.2.0Rust 1.88+Tauri 2
capabilities/standard-dashboard.json — generated from app.toml
{
  "$schema": "../gen/schemas/desktop-schema.json",
  "identifier": "standard-dashboard",
  "description": "Main window: reads application state and receives platform events. No filesystem, no shell, no process execution. Generated from app.toml — do not edit.",
  "windows": [
    "main"
  ],
  "permissions": [
    "core:default",
    "core:event:allow-listen",
    "core:event:allow-unlisten"
  ]
}
crates on crates.io, all at 0.2.0
29
binding rules in ARCHITECTURE.md
15
architecture decision records
31
named security profiles instead of permission lists
4

What it does

  1. Domain code does not know Tauri exists

    Tauri is the desktop host. The application is a set of Rust components that depend on traits, not on an AppHandle, and the whole of it is testable without starting Tauri.

  2. Least privilege, checked by the build

    Each window gets a named security profile. Notifications and URL opening happen in Rust, so the frontend needs no permission for either, and cargo xtask validate fails on a blanket fs:* or shell:* grant.

  3. OAuth and sync that do not cut corners

    PKCE always, state verified before the code is used, a loopback redirect and single-flight refresh. The sync engine owns scheduling: retry, backoff with jitter, offline handling.

  4. Contracts generated, not mirrored

    Capability files come from app.toml and IPC types from their Rust definitions. A rename in Rust fails CI instead of surfacing as undefined in production.

  5. Bring your own AI client

    MCP makes the application controllable by the AI the user already has, with a permission level of its own that defaults to read and propose.

Generated at build time

All examples →
// Generated from PulseSnapshot in src-tauri/src/pulse.rs. Do not edit.

import type { Alert, Health, Metric } from "@casoon/origin-client";

export type PulseSnapshot = { health: Health, metric: Metric | null, alerts: Array<Alert>, };

Derived from the Rust struct PulseSnapshot with ts-rs. The demo's test suite fails when this checked-in file drifts from the declaration.

examples/demo/src/pulse.generated.ts

Quickstart

Run the reference application: a tray app with a background loop, cached read model, typed events, native notifications and a Svelte 5 frontend that never calls invoke directly.

  1. Install Rust 1.88+, Node 22+, pnpm 10+ and the Tauri CLI.
  2. Clone the repository and run pnpm install.
  3. Start the demo with cargo xtask demo, then read its composition root.
terminalShell
git clone https://github.com/casoon/origin
cd origin
pnpm install
cargo xtask demo
the same app, in a testRust
let application = ApplicationBuilder::in_memory()
    .clock(Arc::new(FakeClock::new(now)))
    .notifications(Arc::new(RecordingNotificationService::new()))
    .module(PulseModule)
    .build()?;