Skip to content
Origin
MITDocumentation
Rust · Tauri · Reference architecture · Open source

Domain code does not know
that Tauri exists

Origin is not a framework that replaces Tauri, and not a monolithic crate. It is a set of binding architecture rules, reusable platform crates and build processes – plus a reference application that demonstrates all of it.

Testable without Tauri

The architecture’s quality gate: cargo test --workspace runs without a desktop session.

Machine-checked

cargo xtask validate fails the build when a crate under crates/ depends on tauri.

Usable on their own

The origin-* crates are published on crates.io and stay usable outside Origin.

As of September 2026 · v0.2.0
18
Platform crates
10
Adapters
31
Architecture decision records
forbid
unsafe_code across the workspace
01 — Overview

A new desktop app should not have to reinvent auth, storage and sync.

Origin collects the parts that come up again in every desktop application – authentication, storage, synchronisation, permissions, notifications, logging, project structure – and keeps them as independent Rust crates. Tauri stays the host, not the foundation.

Documentation →
  1. 01Rules, not conventions — 15 binding architecture rules, checked by cargo xtask validate
  2. 02Contract tests — every swappable implementation passes the same suite, in-memory double and system keychain alike
  3. 03Typed eventsbus.subscribe::<PlatformEvent>() instead of bus.on("sync:done"); a renamed field is a compile error
  4. 04Reasoned decisions — 31 ADRs record why a rule reads the way it does, and how to deviate on the record
02 — How it works

Contracts at the bottom, adapters above, Tauri on the outside.

  1. crates/

    Platform and contracts

    18 crates from origin-domain through origin-auth, origin-sync and origin-jobs to origin-app. None of them may know tauri or any tauri-plugin-*.

    origin-domainorigin-app
  2. adapters/

    Concrete implementations

    SQLite, the system keychain, reqwest, an RFC 8252 loopback redirect, MCP over stdio and HTTP, workspace file access and watching – ten of them, all swappable.

    SQLitekeyringreqwest
  3. host/origin-tauri

    The desktop host

    Plugin wiring, tray, IPC commands and the event bridge. One of several equal driving adapters – an MCP server, a CLI and headless operation sit next to it.

    Tauri 2IPC
  4. frontend/

    The only place with IPC

    @casoon/origin-client is the only package that knows Tauri IPC exists; @casoon/origin-ui carries Svelte 5 components and design tokens. Views never call a Tauri API directly.

    TypeScriptSvelte 5
  5. app.toml + xtask

    A manifest instead of copied config

    The manifest says what the product is; cargo xtask generate derives capability files and TypeScript contracts from it. Generated files are Origin-owned and never hand-edited.

    app.tomlgenerate --check
03 — Layers

Dependencies point downwards only.

ARCHITECTURE.mdLayer model
PRODUCT APP            examples/demo, later other independent products
  ↓ composition root
DRIVING ADAPTERS       Tauri host · MCP server · CLI · headless — all equal peers
APPLICATION MODULES    ApplicationModule implementations
  ↓
CONNECTORS             external service integrations
  ↓
ORIGIN PLATFORM        crates/origin-{events,secrets,settings,storage,http,auth,
                       accounts,connector,sync,jobs,mcp,ai,telemetry,app}
TOOLING                crates/origin-{manifest,xtask} — build time, not runtime
  ↓
PLATFORM CONTRACTS     crates/origin-platform, crates/origin-domain (ports)
  ↓
TAURI HOST             host/origin-tauri, adapters/origin-*-tauri
04 — Platform

What an application gets for free.

One error model

Adapters translate rusqlite, reqwest and tauri errors into AppError at the boundary. The frontend branches on kind instead of on error strings.

OAuth without shortcuts

PKCE always, state verified before the code is used, a loopback redirect instead of a custom URL scheme, single-flight refresh. A refresh response without a refresh_token keeps the old one.

The engine owns the schedule

A connector says how to fetch; origin-sync decides when – with backoff, jitter, offline handling and validators. It is tested by moving a fake clock, not by sleeping.

Credentials in the OS keychain

Never in the application database, addressed per account. Disconnecting an account clears everything stored under it by namespace convention – and nothing beyond it.

Least privilege as a profile

Capabilities are set per window as a named security profile, such as local-workspace or account-settings. A blanket fs:* or shell:* fails the build.

A boundary for the AI

MCP makes the application controllable by the AI client the user already has. The permission levels are read, propose, commit and delete; the last two need a grant and a human confirmation.

05 — Two files

The composition root and the manifest.

tests/application.rsRust
let application = ApplicationBuilder::in_memory()
    .clock(Arc::new(FakeClock::new(now)))
    .notifications(Arc::new(RecordingNotificationService::new()))
    .module(PulseModule)
    .build()?;
app.tomlManifest
[origin]
version = "0.2.0"

[product]
id = "dev.casoon.gitbit"
name = "Gitbit"
version = "0.1.0"
description = "GitHub desktop workspace"

[platform]
tray = true
notifications = true
single_instance = true
window_state = true

[security.windows]
main = { profile = "local-workspace" }
settings = { profile = "account-settings" }

[security.process]
allowed_programs = ["code", "cursor", "open", "xdg-open", "git", "github"]
06 — Applications

Four products, four ways of using it.

Private repository

Timbra

Timetabling for schools, vocational schools and universities. A Tauri desktop app with a Svelte 5 frontend that carries the origin-* crates inside its own repository rather than consuming them.

TauriSvelte 5Crates carried along
Private repository

Avilo

Resource-based appointment and patient planning for practices: one appointment can hold several patients, several staff members and several resources at once. Also with carried-along crates, origin-ai and MCP over stdio included.

Tauriorigin-aiMCP
Private repository

Gitbit

A GitHub workspace for the desktop – notifications, issues, pull requests, Projects and local clones. It consumes origin-* = "0.2" as a regular dependency from crates.io, origin-tauri and the workspace adapters included.

crates.ioOrigin 0.2
Private repository

Kestrel

A market-data terminal that deliberately takes a subset: origin-domain, origin-app, origin-secrets, origin-secrets-system and origin-manifest – without origin-tauri. The proof that the crates carry on their own.

Subsetno origin-tauri
07 — Get started

Look at the reference, scaffold a project, check the rules.

  1. 1Requirements

    Install the tools

    Rust 1.88 or newer, Node 22 or newer, pnpm 10 or newer. On Linux the Tauri system packages come on top.

    cargo install tauri-cli --version "^2"
  2. 2Reference

    Run the reference application

    Builds and runs the demo: a tray app with a background loop, a cached read model, typed events and native notifications.

    pnpm install && cargo xtask demo
  3. 3New project

    Scaffold a product from the template

    Creates a project from templates/app that depends on the published origin-* crates as regular registry dependencies.

    cargo xtask new my-app --name "My App" --id dev.example.myapp
  4. 4Check

    Enforce the rules

    ci runs fmt, clippy, tests, the generated-file check and validate – the same steps as in CI.

    cargo xtask ci

Development status · As of September 2026

Implemented

Platform and reference application

The architecture contract, the platform contracts, the Tauri host layer, OAuth with PKCE, account management, the connector contract, the sync engine, background jobs, workspace and process contracts with their adapters, MCP over stdio and authenticated loopback HTTP, the app manifest with generated capabilities – and a running reference application.

In progress

Version 0.2.0, pre-1.0

The crates are published at 0.2.0 on crates.io, the frontend packages at the same version on npm. Contracts may still change before 1.0; cargo xtask update runs the migrations between two Origin versions and hands back a checklist for everything only a human can decide.

Open

Distribution

The template carries a tag-driven release workflow that builds unsigned by default and states in the log what the artifact is. None of it is verified end to end – there is no signed product yet. In-app updates are off in the manifest for security reasons as long as no signing key exists.

08 — Limits

What Origin is not.

Origin takes the repetitive decisions off an application. It does not take away the work on the application’s own subject.

No replacement for Tauri

Tauri stays the host with its plugins, its webview and its build. Origin only settles which layer is allowed to sit where.

No ready-made features

There is no shipped interface and no domain logic. What the product can do, the product writes – Origin supplies the contracts underneath.

Pre-1.0

Version 0.2.0 is an early release. Contracts may change, even though the migrations are tested against frozen fixture projects.

Distribution is groundwork

Signing, notarisation and in-app updates are laid out in the template but never run end to end. Shipping today means expecting your own work at that point.

Desktop, not web or mobile

The platform contracts describe desktop capabilities: keychain, tray, filesystem, local processes. For web or mobile targets this is the wrong shape.

09 — FAQ

Frequently asked questions.

Do I have to adopt all origin crates?

No. The crates are published individually on crates.io and are deliberately cut context-free. Kestrel, for example, uses only origin-domain, origin-app, origin-secrets, origin-secrets-system and origin-manifest, and leaves out origin-tauri.

How is the rule enforced that domain code knows nothing about Tauri?

By cargo xtask validate. The task checks the dependency direction between crates/, adapters/, host/ and examples/, forbids blanket fs:* and shell:* capabilities, and verifies that every command the frontend calls by name exists as a #[tauri::command]. The same task runs in CI.

What happens when I update to a new Origin version?

Every project records in app.toml which Origin version it tracks. cargo xtask update runs the migrations between that version and the current one, regenerates the Origin-owned files, and hands back a checklist for the points that need a decision. The migrations are tested against frozen fixture projects.

How do the frontend and the Rust core connect?

Through @casoon/origin-client, the only package that knows Tauri IPC exists. The TypeScript types for platform IPC and for a product’s own command results are derived from the Rust definitions rather than maintained in parallel. A rename in Rust fails CI instead of surfacing as undefined in production.

What role does MCP play?

In Origin, MCP is a driving adapter on equal footing with the Tauri host: the application exposes tools an external AI client may invoke. The permission levels are read, propose, commit and delete, with the reading ones as the default. Mutating calls need an explicit grant and a human confirmation; if it is missing or fails, the call is denied.

May I deviate from a recommendation?

Yes, but not silently. A deviation belongs either under [origin.overrides] in the app manifest or in adr/ as an ADR. New abstractions follow the Promotion Rule from ADR-0009: a feature starts where it is needed and moves into the platform only once a genuinely neutral shape has emerged – in practice at the third occurrence.

Decide once where each layer belongs.

Origin is open, MIT-licensed and fully on GitHub – with a reference application, a project template and 31 decision records.