app shell with ready to use app engine https://unique-digital-resources.github.io/AppShell-Documentation/
It is still in the early stages of development.
A dependency-free application runtime and domain foundation for Rust.
App Engine (runtime infrastructure) + Domain Foundation (reusable domain models) — all in one coherent library.
Features · Quick Start · Architecture · Guides
AppShell is a two-layer library for building Rust applications:
- App Engine — generic application runtime infrastructure (lifecycle, commands, tasks, scheduling, events, signals, history, resources, services, plugins, configuration) without knowing what your application does.
- Domain Foundation — reusable, headless domain models (Canvas2D, Timeline, Layers, NodeGraph, Viewport3D, Table, TextEditor, Relations, Utilities) that sit between the App Engine and your application-specific Domain Engine.
flowchart TD
subgraph AE["APP ENGINE"]
EX["Execution<br/>Commands<br/>Tasks<br/>Scheduler<br/>Resources"]
CM["Communication<br/>Events<br/>Signals<br/>History"]
XT["Extension<br/>Plugins<br/>Services<br/>Permissions"]
SP["Supporting<br/>Runtime + Lifecycle (+ cleanup)<br/>Context + State (thread-safe)<br/>Configuration + Preferences (+ persistence)<br/>Execution Control (cancel, deadline, stream)<br/>Concurrency (thread-safe, async, TaskPool)<br/>Serialization (Serializer, registry, IPC)<br/>Testing (mocks, TestEngine, assertions)<br/>Metadata (Version, PayloadSchema)"]
RL["Reliability<br/>Panic isolation (catch_unwind)<br/>Event priority (High/Normal/Low)<br/>Retry policies (Fixed/Exponential)<br/>RAII resource handles (auto-release)"]
end
subgraph DF["DOMAIN FOUNDATION"]
ENV["Environments<br/>Canvas2D, Timeline, Layers<br/>NodeGraph, Viewport3D, Table, TextEditor"]
REL["Relations<br/>Priority-sorted evaluation<br/>Batch propagation<br/>Value source/sink traits"]
UTIL["Utilities<br/>Filtering, Querying, Tagging<br/>Sorting, Grouping, Validation, Batch"]
end
AE -->|"contracts"| DF
DF -->|"composes"| DE["DOMAIN ENGINE<br/>(app meaning)"]
DE -->|"integration"| API["API / MCP / UI"]
Zero external dependencies by default. Optional tokio for async. Optional serde for serialization.
| Feature | App Engine | Domain Foundation | bevy_app | tokio | iced | tauri |
|---|---|---|---|---|---|---|
| Lifecycle | ✅ 5-state | — | ✅ | ❌ | ❌ | ❌ |
| Commands | ✅ | — | ❌ | ❌ | ❌ | ❌ |
| Tasks | ✅ | — | ❌ | ✅ | ❌ | ❌ |
| Scheduler | ✅ | — | ❌ | ✅ (async) | ❌ | ❌ |
| Events | ✅ priority + isolation | — | ❌ | ❌ | ❌ | ❌ |
| Signals | ✅ thread-safe | — | ❌ | ❌ | ✅ | ❌ |
| History | ✅ undo/redo/replay | — | ❌ | ❌ | ❌ | ❌ |
| Resources | ✅ RAII + deps | — | ❌ | ❌ | ❌ | ❌ |
| Services | ✅ panic-isolated | — | ✅ | ❌ | ❌ | ❌ |
| Plugins | ✅ permissions | — | ✅ | ❌ | ❌ | ✅ |
| Config | ✅ persistent | — | ❌ | ❌ | ❌ | ✅ |
| Persistence | ✅ file/memory | — | ❌ | ❌ | ❌ | ❌ |
| Serialization | ✅ zero deps | ✅ optional serde | ❌ | ❌ | ❌ | ❌ |
| Concurrency | ✅ Send + Sync | ✅ Send + Sync | ✅ | ✅ | ❌ | ❌ |
| Async | ✅ optional tokio | — | ❌ | ✅ | ❌ | ❌ |
| Panic isolation | ✅ all handlers | — | ❌ | ❌ | ❌ | ❌ |
| 2D Canvas | — | ✅ headless | ❌ | ❌ | ❌ | ❌ |
| Timeline | — | ✅ headless | ❌ | ❌ | ❌ | ❌ |
| Layers | — | ✅ hierarchy | ❌ | ❌ | ❌ | ❌ |
| NodeGraph | — | ✅ + Canvas2D | ❌ | ❌ | ❌ | ❌ |
| Viewport3D | — | ✅ headless | ❌ | ❌ | ❌ | ❌ |
| Table | — | ✅ + merged cells | ❌ | ❌ | ❌ | ❌ |
| TextEditor | — | ✅ Unicode | ❌ | ❌ | ❌ | ❌ |
| Relations | — | ✅ priority + batch | ❌ | ❌ | ❌ | ❌ |
| Undoable ops | — | ✅ all operations | ❌ | ❌ | ❌ | ❌ |
| Dependencies | zero by default | zero by default | many | tokio | many | many |
| System | What It Does |
|---|---|
| Commands | Application intents — "do X." Registered, executed, panic-isolated. |
| Tasks | Managed work with lifecycle: Pending → Running → Completed/Failed/Cancelled. Cancellation, deadlines, progress streaming. |
| Scheduler | Decides when tasks run: immediate, delayed, interval, triggered. Priority queue. Retry policies with fixed/exponential backoff. |
| Resources | Load, cache, track, and release generic data. RAII handles auto-release on drop. Dependency tracking. Thread-safe. |
| System | What It Does |
|---|---|
| Events | "Something happened." One-to-many, priority-ordered, panic-isolated. Serialized payload support for IPC. |
| Signals | "Something changed." Lightweight, thread-safe. Progress streaming from task handlers. |
| History | Ordered operations with undo/redo/replay/transactions. Persistence-ready. |
| System | What It Does |
|---|---|
| Services | Long-lived capabilities that start/stop with the app. Panic-isolated lifecycle. |
| Plugins | Extension packages contributing commands, tasks, resources, services, handlers. Permission-controlled. Dynamic loader stub for .so/.dll. |
| System | What It Does |
|---|---|
| Runtime + Lifecycle | Owns the application lifetime. Cancels tasks on stop. Unloads resources on dispose. |
| Context | Identity hierarchy: Application → Session → Execution. |
| State | Generic key-value state store with validated transitions. Thread-safe. |
| Configuration | Persistent settings. File/memory backends. Change notifications. Thread-safe. |
| Preferences | User-facing settings. Thread-safe. |
| EngineRef | Read-only bundle of subsystems passed to handlers. Handlers can publish events, load resources, write config, submit to scheduler. |
| Execution Control | CancellationToken, Deadline, TaskOutputChannel. |
| Persistence | StorageBackend trait with FileStorageBackend and MemoryStorageBackend. |
| Serialization | Serializer trait + SerializationRegistry. Serialized bytes on all payloads for IPC. Zero external deps. |
| Concurrency | All managers Send + Sync. TaskPool. Optional AsyncRuntime (tokio). |
| Panic Isolation | All handler calls wrapped in catch_unwind. Mutex not poisoned. |
| Testing | MockCommandExecutor, MockEventBus, MockSignalBus, TestEngine, assertion helpers. |
| Metadata | Version, PayloadSchema on all definitions. |
| Environment | What It Does |
|---|---|
| Canvas2D | Arbitrary 2D spatial organization with objects, transforms, z-ordering, spatial queries. |
| Timeline | Temporal organization with tracks, clips, keyframes, interpolation, overlap constraints. |
| Layers | Hierarchical organization with parent-child, visibility inheritance, reparenting. |
| NodeGraph | Graph connectivity with ports, edges, type matching, topological sort. Composes Canvas2D. |
| Viewport3D | 3D spatial organization with Euler angles, parent-child transforms, spatial queries. |
| Table | Tabular data with rows, columns, cells, merged cells, ordering, swap operations. |
| TextEditor | Headless text editing with Unicode positions, ranges, search/replace, line/column. |
| Feature | What It Does |
|---|---|
| Definitions | Declarative relation metadata: endpoints, trigger, propagation mode, priority. |
| Evaluation | Apply developer-supplied effect closures when source properties change. |
| Propagation | Direct or cascading with cycle protection and max depth. |
| Batch | Accumulate multiple property changes and propagate together. |
| Value Source/Sink | Traits for bridging Domain Engine state to evaluation engine. |
| Utility | What It Does |
|---|---|
| Filtering | Composable predicates (AND/OR/NOT) over any data type. |
| Querying | Named, reusable queries built on filtering. |
| Tagging | Tags and tag sets with deterministic iteration (BTreeSet). |
| Sorting | Criteria-based ordering, in-place or non-mutating. |
| Grouping | Group by key, with deterministic sorted output. |
| Validation | Rules, multi-rule validation, collect all failures. |
| Batch | Multi-object operations via trait or closure. |
use app_shell::app_engine::*;
use std::any::Any;
// --- Your command handler ---
struct GreetCommand;
impl CommandHandler for GreetCommand {
fn execute(
&self,
input: &CommandInput,
_: &CommandContext,
engine: &EngineRef,
) -> Result<CommandResult, CommandError> {
let name: &String = input.get::<String>()
.ok_or_else(|| CommandError::InvalidArguments("expected name".to_string()))?;
engine.event_bus.publish(
&Event::new("greet.done").with_source("GreetCommand")
);
Ok(CommandResult::success_with(format!("Hello, {}!", name)))
}
}
// --- Main ---
fn main() {
let mut engine: AppEngine = Bootstrap::create().expect("bootstrap failed");
engine.command_executor_mut().register(
CommandDefinition::new("app.greet", "Greet", "Greet someone"),
Box::new(GreetCommand),
).unwrap();
engine.initialize().unwrap();
engine.start().unwrap();
let cmd = Command::new(
"app.greet",
CommandContext::new(ExecutionId::new()),
CommandInput::new("World".to_string()),
);
let result = engine.execute_command(&cmd).unwrap();
println!("{}", result.output::<String>().unwrap());
engine.stop().unwrap();
engine.dispose().unwrap();
}use app_shell::domain_engine::DomainEngine;
use app_shell::domain_foundation::environments::canvas_2d::*;
let mut engine = DomainEngine::new();
// Create a canvas object
let id = engine.execute_canvas(CanvasOperation::Create {
transform: Transform::from_translation(Vec2::new(100.0, 200.0)),
}).unwrap();
// Move it
engine.execute_canvas(CanvasOperation::Move {
id,
translation: Vec2::new(50.0, 50.0),
}).unwrap();
// Undo
engine.undo().unwrap();
assert_eq!(
engine.canvas().get(id).unwrap().transform.translation,
Vec2::new(100.0, 200.0),
);
// Transactions
engine.begin_transaction();
engine.execute_canvas(CanvasOperation::Create { transform: Transform::identity() }).unwrap();
engine.execute_canvas(CanvasOperation::Create { transform: Transform::identity() }).unwrap();
engine.commit_transaction();
// Undo both as one unit
engine.undo().unwrap();
assert_eq!(engine.canvas().len(), 0);flowchart TD
R["Runtime"] --> C["Context"]
R --> S["State"]
R --> CF["Configuration"]
S --> G1["Commands<br/>Tasks<br/>Scheduler<br/>Resources"]
G1 --> G2["Events<br/>Signals<br/>History"]
G2 --> G3["Services<br/>Plugins<br/>Preferences"]
Domain Engine ──→ Domain Foundation ──→ App Engine ──→ (nothing)
App Engine ✗→ Domain Foundation
Domain Engine ✗→ App Engine (directly)
App Engine ✗→ UI / API / MCP
flowchart TD
A["External Layer (UI / API / MCP / CLI)"] -->|"commands"| B["Domain Engine (application meaning)"]
B -->|"composes"| C["Domain Foundation (reusable domain models)"]
C -->|"uses contracts"| D["App Engine (runtime infrastructure)"]
Each layer knows only the layer below it. The App Engine never imports domain types. The Domain Foundation never imports UI types.
Add to your Cargo.toml:
[dependencies]
app_shell = { path = "path/to/AppShell" }
# Optional: async runtime
app_shell = { path = "path/to/AppShell", features = ["async-runtime"] }
# Optional: serialization
app_shell = { path = "path/to/AppShell", features = ["serde"] }| Feature | Description |
|---|---|
default |
Zero external dependencies. All systems included (sync only). |
async-runtime |
Adds tokio for async task execution via AsyncTaskHandler. |
serde |
Adds serde derives on all serializable Domain Foundation types. |
| Property | App Engine | Domain Foundation |
|---|---|---|
| Dependency-free | ✅ Zero external crates by default | ✅ Zero external crates by default |
| Thread-safe | ✅ All managers are Send + Sync |
✅ All environments are Send + Sync |
| Panic-isolated | ✅ All handler calls wrapped in catch_unwind |
— |
| RAII resources | ✅ Handles auto-release on drop | — |
| Backward compatible | ✅ Default permissions = FULL_ACCESS |
— |
| Headless | ✅ Runs without UI, API, or MCP | ✅ No UI, rendering, or input |
| Serializable | ✅ Serializer trait, zero deps |
✅ Optional serde feature |
| Persistent | ✅ StorageBackend trait, file + memory |
— |
| Testable | ✅ Mocks, TestEngine, assertion helpers |
✅ 414 tests + proptest + benchmarks |
| Versioned | ✅ Version, PayloadSchema on all definitions |
— |
| Async-ready | ✅ Optional tokio integration |
— |
| Composable | — | ✅ Environments compose concretely |
| Undoable operations | — | ✅ Every operation carries undo data |
| Unicode-aware | — | ✅ TextEditor uses Unicode scalar value positions |
| Priority-sorted relations | — | ✅ Higher priority relations fire first |
| Cycle-safe | — | ✅ Propagator + Layer/Viewport3D reject cycles |
flowchart TD
subgraph APPSHELL["APPSHELL"]
subgraph AE["APP ENGINE"]
EX["Execution"]
CO["Communication"]
EN["Extension"]
FO["Foundation"]
RE["Reliability"]
EX --> EX1["Commands (intent → execution, panic-isolated)"]
EX --> EX2["Tasks (managed work, cancel, deadline, progress)"]
EX --> EX3["Scheduler (when work runs, retry, triggers)"]
EX --> EX4["Resources (load, cache, RAII handles, dependencies)"]
CO --> CO1["Events (one-to-many, priority, panic-isolated)"]
CO --> CO2["Signals (lightweight change notifications)"]
CO --> CO3["History (undo/redo/replay/transactions)"]
EN --> EN1["Services (long-lived, panic-isolated lifecycle)"]
EN --> EN2["Plugins (extension packages, permission-controlled)"]
FO --> FO1["Runtime + Lifecycle (+ cleanup on stop/dispose)"]
FO --> FO2["Context (Application → Session → Execution)"]
FO --> FO3["State (generic key-value, thread-safe)"]
FO --> FO4["Configuration (persistent, thread-safe, change notifications)"]
FO --> FO5["Preferences (user-facing, thread-safe)"]
FO --> FO6["EngineRef (handler capabilities)"]
FO --> FO7["Execution Control (cancel, deadline, stream)"]
FO --> FO8["Persistence (StorageBackend trait)"]
FO --> FO9["Serialization (Serializer trait, registry)"]
FO --> FO10["Concurrency (TaskPool, AsyncRuntime)"]
FO --> FO11["Testing (mocks, TestEngine)"]
FO --> FO12["Metadata (Version, PayloadSchema)"]
RE --> RE1["Panic Isolation (catch_unwind on all handlers)"]
RE --> RE2["Event Priority (High/Normal/Low)"]
RE --> RE3["Retry Policies (Fixed/Exponential)"]
RE --> RE4["RAII Handles (auto-release on drop)"]
end
subgraph DF["DOMAIN FOUNDATION"]
ENV["Environments"]
REL["Relations"]
UTI["Utilities"]
ENV --> E1["Canvas2D (objects, transforms, z-order, spatial queries)"]
ENV --> E2["Timeline (tracks, clips, keyframes, interpolation)"]
ENV --> E3["Layers (hierarchy, visibility inheritance, reparenting)"]
ENV --> E4["NodeGraph (ports, edges, type matching, topo sort)"]
ENV --> E5["Viewport3D (3D transforms, parent-child, spatial queries)"]
ENV --> E6["Table (rows, columns, cells, merged cells, ordering)"]
ENV --> E7["TextEditor (Unicode positions, ranges, search/replace)"]
REL --> R1["Definitions (endpoints, trigger, propagation, priority)"]
REL --> R2["Evaluation (effect closures, mutable value store)"]
REL --> R3["Propagation (Direct, Cascading, cycle protection)"]
REL --> R4["Batch (accumulate, commit, rollback)"]
REL --> R5["Value Source/Sink (bridge Domain Engine state)"]
UTI --> U1["Filtering (AND/OR/NOT composable predicates)"]
UTI --> U2["Querying (named, reusable queries)"]
UTI --> U3["Tagging (BTreeSet, deterministic order)"]
UTI --> U4["Sorting (criteria-based ordering)"]
UTI --> U5["Grouping (group by key, sorted output)"]
UTI --> U6["Validation (rules, multi-rule, collect failures)"]
UTI --> U7["Batch (multi-object operations)"]
end
end
AE -->|"contracts"| DF
DF -->|"composes"| DE["DOMAIN ENGINE (app meaning)"]
✅ Use AppShell when:
- You need managed execution (commands, tasks, scheduling)
- You need undo/redo with transactions
- You need reusable domain models (2D canvas, timeline, layers, node graph, table, text editor)
- You need property propagation between objects (relations)
- You need plugin extensibility with permission control
- You need decoupled communication (events/signals)
- You need resource management with RAII handles
- You need long-lived services with panic isolation
- You need thread-safe managers (
Send + Sync) - You need async execution (optional tokio)
- You need serialization for IPC or persistence (zero deps or serde)
- You want stable contracts between runtime, domain models, and domain logic
❌ Don't use AppShell if:
- Your app is a simple script
- You have no lifecycle/undo/extensibility/domain-model needs
- You don't need domain/UI/API separation
Apache-2.0
(Not Yet) Pull requests welcome. See the architecture guide before contributing — clean boundaries are the core value proposition.
| # | Guide | Topic |
|---|---|---|
| 01 | Overview | What App Engine is, what it provides, what it doesn't |
| 02 | Architecture | Layering, boundaries, subsystem ownership |
| 03 | Bootstrap & Lifecycle | Creating, running, shutting down |
| 04 | Context & State | Identity hierarchy, state management |
| 05 | Commands & Tasks | Intents, managed work, registration, execution |
| 06 | Scheduling & Communication | Scheduler, events, signals |
| 07 | History & Resources | Undo/redo, RAII handles, dependencies |
| 08 | Services & Plugins | Long-lived capabilities, extensions, permissions |
| 09 | Domain Engine Integration | How to build your domain layer |
| 10 | Application Integration | UI, API, MCP, CLI, headless |
| # | Guide | Topic |
|---|---|---|
| 11 | Handler Capabilities | EngineRef, what handlers can access |
| 12 | Execution Control | Cancellation, deadlines, progress streaming |
| 13 | Persistence & Serialization | Storage backends, Serializer trait, IPC |
| 14 | Concurrency & Async | Thread safety, TaskPool, AsyncRuntime |
| 15 | Communication & Reliability | Priority, panic isolation, retry |
| 16 | Testing & Metadata | Mocks, TestEngine, Version, PayloadSchema |
| 17 | Plugin Security | Permissions, PermissionCheckedEngineRef |
| # | Guide | Topic |
|---|---|---|
| 18 | Public API Reference | Complete type/trait listing |
| 19 | Error Reference | All error types and variants |
| 20 | Quick Start | 5-minute getting started |
| # | Guide | Topic |
|---|---|---|
| 01 | Overview | What Domain Foundation is, what it provides, what it doesn't |
| 02 | Architecture | Layering, composition rules, dependency direction |
| 03 | Environments | All 7 environments at a glance |
| # | Guide | Topic |
|---|---|---|
| 04 | Canvas2D | 2D spatial: objects, transforms, z-order, spatial queries |
| 05 | Timeline | Temporal: tracks, clips, keyframes, interpolation, overlap |
| 06 | Layers | Hierarchy: parent-child, visibility, locked, reparenting |
| 07 | NodeGraph | Graph: nodes, ports, edges, type matching, topo sort, Canvas2D composition |
| 08 | Viewport3D | 3D spatial: Euler angles, parent-child, spatial queries |
| 09 | Table | Tabular: rows, columns, cells, merged cells, ordering |
| 10 | TextEditor | Text: Unicode positions, ranges, search/replace, line/column |
| # | Guide | Topic |
|---|---|---|
| 11 | Relations | Definitions, evaluation, propagation, batch, value source/sink |
| 12 | Utilities | Filtering, querying, tagging, sorting, grouping, validation, batch |
| # | Guide | Topic |
|---|---|---|
| 13 | Domain Engine Integration | How DomainEngine composes all environments + App Engine |
| 14 | App Engine Integration | Command handlers, EngineRef, history, events, signals |
| 15 | Operations & Undo | Operation pattern, outcomes, undo/redo, transactions, compound ops |
| 16 | Serialization | serde feature, round-trip, known limitations |
| # | Guide | Topic |
|---|---|---|
| 17 | Testing | Model, operation, integration, composition, acceptance, concurrency, proptest, stress |
| 18 | Public API Reference | Complete type/trait listing |
| 19 | Error Reference | All error types and variants |
| 20 | Quick Start | 5-minute getting started with Domain Foundation |
Built with ❤️ in Rust. Zero dependencies. No compromise.