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.
The architecture’s quality gate: cargo test --workspace runs without a desktop session.
cargo xtask validate fails the build when a crate under crates/ depends on tauri.
The origin-* crates are published on crates.io and stay usable outside Origin.
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 →- 01Rules, not conventions — 15 binding architecture rules, checked by
cargo xtask validate - 02Contract tests — every swappable implementation passes the same suite, in-memory double and system keychain alike
- 03Typed events —
bus.subscribe::<PlatformEvent>()instead ofbus.on("sync:done"); a renamed field is a compile error - 04Reasoned decisions — 31 ADRs record why a rule reads the way it does, and how to deviate on the record
Contracts at the bottom, adapters above, Tauri on the outside.
- crates/
Platform and contracts
18 crates from
origin-domainthroughorigin-auth,origin-syncandorigin-jobstoorigin-app. None of them may knowtaurior anytauri-plugin-*. - 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.
- 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.
- frontend/
The only place with IPC
@casoon/origin-clientis the only package that knows Tauri IPC exists;@casoon/origin-uicarries Svelte 5 components and design tokens. Views never call a Tauri API directly. - app.toml + xtask
A manifest instead of copied config
The manifest says what the product is;
cargo xtask generatederives capability files and TypeScript contracts from it. Generated files are Origin-owned and never hand-edited.
Dependencies point downwards only.
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-*-tauriWhat 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.
The composition root and the manifest.
let application = ApplicationBuilder::in_memory()
.clock(Arc::new(FakeClock::new(now)))
.notifications(Arc::new(RecordingNotificationService::new()))
.module(PulseModule)
.build()?;[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"]Four products, four ways of using it.
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.
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.
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.
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.
Look at the reference, scaffold a project, check the rules.
- 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" - 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 - 3New project
Scaffold a product from the template
Creates a project from
templates/appthat depends on the publishedorigin-*crates as regular registry dependencies.cargo xtask new my-app --name "My App" --id dev.example.myapp - 4Check
Enforce the rules
ciruns fmt, clippy, tests, the generated-file check andvalidate– the same steps as in CI.cargo xtask ci
Development status · As of September 2026
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.
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.
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.
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.
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.
Also a good fit.
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.