# Aria
**Repository Path**: gitstr/Aria
## Basic Information
- **Project Name**: Aria
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-10-28
- **Last Updated**: 2026-10-28
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# ⚡ Aria
[Complete dependency update guide](docs/dependency-updates.en.md) — Version pins, selective updates, offline use, rollback and commit steps.
**Modern C++ MVVM for industrial-grade cross-platform software** · C++23 · reactive · coroutine-first
One C++ core. Six platforms. Elegant architecture for complex applications, explicit engineering contracts for long-term evolution.
Windows / macOS / Linux / iOS / Android / Web
[](https://en.cppreference.com/w/cpp/23)
[](LICENSE)
[](https://github.com/dqsjqian/Aria/actions/workflows/ci.yml)
[](#)
[English](README.en.md) | [简体中文](README.md)
---
## 📚 From beginner to expert: AriaTutorial
Want to learn Aria systematically? The companion repository **[AriaTutorial](https://github.com/dqsjqian/AriaTutorial)** is a 20-chapter, bilingual (Chinese/English) progressive tutorial, **each chapter shipping a minimal demo you can compile and run**.
- Every code block in an article is **character-for-character identical** to the source under `demos/`, not a hand-copied illustration;
- Every output block is the demo's **real stdout** on Windows / MSVC, checked automatically by script;
- Every chapter opens with one conclusion figure (data flow, dependency graph, state machine, or timeline) whose numbers also come from the demo's real run;
- The path covers: reactive core → collections and forms → binding and adapters → async, diagnostics and testing → a complete application.
## 🌟 Flagship example: AriaTools
Start with [AriaTools](https://github.com/dqsjqian/AriaTools) to see Aria in a real application. It is Aria's single flagship cross-platform example, driving Qt, iOS, Android, and Web from one C++ ViewModel. This repository now stays focused on the framework, acceptance tests, and minimal documentation snippets.
## 🚀 Aria in 30 seconds
Aria splits a screen in two. The **ViewModel** is plain C++ and knows nothing about any
UI library; the **View** is native widgets. `BindingEngine` joins them, and it only ever
talks to the `IViewAdapter` interface — so porting means swapping the adapter, nothing else.
**Upper half — the ViewModel (plain C++, unit-testable, shared by every platform)**
```cpp
// Splitting a bill: total ÷ people = each person's share.
struct BillViewModel {
aria::Property bill{100.0}; // read-write state
aria::Property people{2};
// Computed is a read-only derived value. You never write its
// dependency list: the first evaluation reads bill and people, and
// those two are recorded as its dependencies automatically.
aria::Computed per_person{[this] {
return bill.get() / people.get();
}};
};
```
There is no UI in that code and no UI header included — it runs under a console test.
**Lower half — wiring up the View (a dozen lines per platform; the UI itself stays native)**
First, the thing most likely to be misread: **you do not write the UI in C++.** Buttons,
layout and animation are still authored the usual way — Qt Designer, Storyboard, Compose,
HTML. The code below only hands widgets that already exist over to the engine, and the
three steps never change: ① construct the platform adapter ② build a `BindingEngine` from
it ③ bind a widget to a Property.
Qt6 (Windows / macOS / Linux · plain C++)
```cpp
auto adapter = std::make_shared();
aria::binding::BindingEngine engine{adapter};
BillViewModel vm;
// label_view wraps the QLabel you dragged out in Qt Designer
aria::adapters::qt6::QtView label_view{real_label};
engine.bind_text_projected(vm.per_person, label_view,
[](double v) { return std::format("¥{:.2f}", v); });
```
iOS / UIKit (the wiring file is Objective-C++ .mm; the UI is still Storyboard / SwiftUI)
```objc++
#import "aria/adapters/uikit/UIKitAdapter.hpp"
auto adapter = std::make_shared();
aria::binding::BindingEngine engine(adapter, ui_dispatcher,
aria::binding::BindingEngine::DispatchPolicy::SmartMarshal);
// Wrap the UILabel* from your Storyboard so C++ can bind to it
auto label = std::make_shared(self.totalLabel);
engine.bind_text_projected(vm.per_person, *label,
[](double v) { return std::format("¥{:.2f}", v); });
```
`UIKitView` retains the `UIView*` under ARC and, on destruction, tells `BindingEngine` to
drop its subscriptions while the native view is still valid — so no callback ever reaches a
released widget.
macOS / AppKit (same shape: .mm + NSView)
```objc++
#import "aria/adapters/appkit/AppKitAdapter.hpp"
auto adapter = std::make_shared();
aria::binding::BindingEngine engine(adapter, ui_dispatcher,
aria::binding::BindingEngine::DispatchPolicy::SmartMarshal);
auto label = std::make_shared(self.totalField);
engine.bind_text_projected(vm.per_person, *label, /* ... */);
```
Android (UI in Kotlin / Compose; C++ only does the wiring)
```cpp
// Called on the Android UI thread with real android.view.View objects
auto adapter = std::make_shared(env);
aria::binding::BindingEngine engine(adapter);
aria::adapters::jni::JniView total_view(env, total_text_view);
engine.bind_text_projected(vm.per_person, total_view,
[](double v) { return std::format("¥{:.2f}", v); }); // → TextView
```
Kotlin-side listeners forward native events back in (`adapter->notify_text_changed(...)` /
`notify_click(...)`), so **listener ownership stays on Android** while the C++ side stays
strongly typed. Compose has no addressable view object; use the side-channel shape from the
adapter guide.
Web (no C++ in the browser — the frontend is HTML/JS, C++ runs server-side)
```cpp
aria::adapters::http::HttpAdapterConfig config;
config.port = 9090;
auto http = std::make_shared(config);
// Here a "widget" is a string ID matching a DOM element in the browser
auto& total = http->register_view("total", "text");
aria::binding::BindingEngine engine{http};
engine.bind_text_projected(vm.per_person, total,
[](double v) { return std::format("¥{:.2f}", v); });
http->start(); // Property changes go out over SSE; user input comes back over REST
```
**That is the point**: five wiring snippets that look nearly identical, and the
`BillViewModel` above is byte-for-byte unchanged across all of them. Porting costs you
those dozen lines, not your business logic.
**After wiring — mutate data, the UI follows**
Once bound, the rest is platform-independent. The code below behaves identically on all
five platforms, and **not one line of refresh code is written by hand**:
```cpp
BillViewModel vm; // per_person = 100/2 = ¥50.00
// ... bound to a label via any of the platforms above ...
vm.people = 4; // label → ¥25.00
vm.bill = 200.0; // label → ¥50.00
```
Change either `bill` or `people` and `per_person` recomputes and pushes to the label —
because its dependencies were recorded automatically on the `Computed`'s first evaluation.
You never wrote anything resembling "when people changes, update the label".
One detail worth knowing when you change several values in a row:
```cpp
// One at a time → one push each, so the label flashes an intermediate value
vm.bill = 300.0; // label → ¥150.00 ← intermediate
vm.people = 4; // label → ¥75.00
// Wrapped in batch → a single push at the end, no intermediate state
aria::reactive::batch([&] {
vm.bill = 1200.0;
vm.people = 8;
}); // label → ¥150.00 (once)
```
And a convenient default: **if the final result equals the current value, nothing is
notified at all.** Following on from above, a batch setting `bill=600, people=4` (still
150) leaves the label untouched.
The whole architecture in one picture — upper half is the pure C++ ViewModel, the middle
is `BindingEngine` (which only knows the `IViewAdapter` interface), and the bottom row is
the five native adapters:

Continue with the [binding guide](docs/guide/binding.md), the [per-platform adapter guides](docs/guide/adapters/), the [cookbook](docs/cookbook/README.md), or the full four-platform [AriaTools](https://github.com/dqsjqian/AriaTools) application.
## 🎯 Design philosophy and engineering strength
Aria brings **reactive state, asynchronous coroutines, and cross-platform binding into one modern C++ architecture, independent of UI toolkits**. Implement complex business logic once and give each platform its native experience.
Elegance comes from clear responsibilities: a ViewModel is an ordinary C++ class, with no required framework base class, macros, or code generator.
UI layers connect through `IViewAdapter`. Qt6 / AppKit / UIKit / JNI / HTTP share one binding protocol, so changing UI toolkits leaves the ViewModel intact.
**Built to the engineering standards of world-class industrial software.** Lifecycle, threading, error handling, and collection events have traceable [engineering contracts](docs/index.md#reference), checked through automated tests, fuzz testing, and reproducible [performance benchmarks](docs/reference/performance.md). Architectural elegance carries through to state updates, asynchronous cancellation, and cross-platform delivery.
| Architectural strength | Engineering design |
|---|---|
| **Modern C++ foundation** | C++23 baseline (GCC 16+ / Clang 23+ / AppleClang from Xcode 27+ / MSVC v145, i.e. Visual Studio 2026) with full coroutines and concepts. Integrating projects must use C++23 or later. |
| **Native UI freedom** | Your UI toolkit owns widgets, layout, and animation. Aria unifies one-way and two-way state binding, sharing the business core while preserving native experiences. |
| **Layered compatibility** | `aria-abi` / `aria-runtime` / `aria-binding` maintain ABI stability within a major version, with matching compiler, standard library, and build options. Rebuild templates such as `Property` and their containing types after updates. |
| **Open adapter protocol** | Qt6 / AppKit / UIKit / JNI / HTTP ship out of the box. Integrate other UI toolkits by implementing `IViewAdapter` (see the [adapter guides](docs/guide/adapters/)). |
| **Applications and learning resources** | AriaTools, AriaAgent, and AriaRead demonstrate cross-platform workbenches, agent GUIs, and reading engines. [Guides](docs/index.md), the [Cookbook](docs/cookbook/README.md), and engineering contracts cover the path from first integration to custom extensions. |
**Designed for shared C++ business logic, native multi-platform UIs, and long-term maintenance.** Aria owns business state and binding; the chosen UI toolkit owns rendering and UI reuse. An explicit adapter protocol connects the two.
## ✨ Core features
- 📦 **Template-based reactive core** — `Property` / `Computed` / `Effect` / `Command<>` / `ObservableList` / `Validator` share one reactive dependency-graph engine. `Computed` auto-tracks deps; `reactive::batch` / `reactive::untracked` for fine control.
- 🔌 **Shared foundation and ABI layer** — `aria::core` automatically links `aria::abi` for shared graph, diagnostics and signal storage. Binary compatibility requires matching compiler, standard library, build options and major version. Rebuild template code and its containing types after updates.
- ⚡ **C++ coroutines** — `Task`, executors, `co_await schedule_on(pool)`. Async code reads like sync code.
- 🖥 **Adapter abstraction** (`IViewAdapter`) — Qt6 / AppKit / UIKit / JNI / HTTP. Any UI toolkit, same business logic.
## 🏗 Architecture (10 modules)
```
┌────────────────────────────────────────────────────────────────────────┐
│ Application │
└────────────────────────────────┬───────────────────────────────────────┘
┌──────────────────┼──────────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Qt6 adapter │ │ JNI adapter │ │ HTTP adapter │ (optional
│ (Win/Mac/Lin)│ │ (Android) │ │ REST/SSE Web │ modules;
│ AppKit/UIKit │ │ │ │ Web browser │ opt-in)
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
└───────────────────┴───────────────────┘
▼
┌─────────────────────────────────┐
│ aria-binding (SHARED) │
│ BindingEngine + IViewAdapter │
└────────────────┬────────────────┘
│
┌──────────────────────┴───────────────────────┐
▼ ▼
┌───────────────────┐ ┌────────────────────┐
│ aria-runtime │ │ aria-async │
│ (SHARED .dylib) │ │ (header-only) │
│ EventBus │ │ Task │
│ Container │ │ Scheduler │
│ Dispatcher │ │ Executor │
│ Logger │ │ schedule_on │
└───────┬───────────┘ └─────────┬──────────┘
└──────────────────┬─────────────────────────—┘
▼
┌─────────────────────────────┐
│ aria-core (header-only) │
│ Property / Computed / Cmd │
│ ObservableList / Validator │
│ Subscription │
└──────────────┬──────────────┘
▼
┌─────────────────────────────┐
│ aria-abi (SHARED) │
│ Type-erased Signal/Slot │
│ ABI-stable, no templates │
└─────────────────────────────┘
```
| Module | Type | Depends on | Notes |
|--------|------|-----------|-------|
| `aria-abi` | `SHARED` by default | Threads | Compiled foundation: signals, shared reactive graph, diagnostics storage, scheduler base, and version metadata. Static builds are supported. |
| `aria-core` | header-only | abi | All the templates: `Property`, `Computed`, `Command`, `ObservableList`, `Validator`. Source-compatible only (not ABI-stable). |
| `aria-async` | header-only | core | Coroutine `Task`, executors. Source-compatible only. |
| `aria-runtime` | `SHARED` | core, abi | EventBus / Container / Dispatcher / Logger — singletons live in **one** dylib. **ABI-stable** (non-template exports). |
| `aria-binding` | `SHARED` | core, runtime | `BindingEngine`, `IViewAdapter`. **ABI-stable** (non-template exports). |
| Adapters | `SHARED`/`STATIC` | binding | Qt6 / AppKit / UIKit / JNI / HTTP (each opt-in). WASM is conditional roadmap work. |
## 📋 Requirements
- **CMake** >= 3.21
- **Compiler** with full C++23 support:
- GCC >= 16 (the MSYS2 UCRT64 toolchain on Windows)
- Clang >= 23 (on macOS / iOS, the AppleClang of Xcode 27 or newer)
- **MSVC v145 / Visual Studio 2026** (current Windows CI toolchain, see below)
- *(optional)* **Qt6** >= 6.4 (for the Qt6 adapter)
> **Windows is supported on two toolchains: MSYS2 UCRT64 (GCC) and
> MSVC / Visual Studio 2026.** Pick whichever fits your team's existing
> stack — both build the full framework + tests + adapters from a single
> tree, no source forks. See ["Windows toolchains"](#windows-toolchains) below.
## 🚀 Quick start
```bash
git clone https://github.com/dqsjqian/Aria.git
cd Aria
python -m pip install -r requirements-build.txt
python -m forgedeps init /path/to/shared-dependencies
cmake -B build/flavors/release -DCMAKE_BUILD_TYPE=Release
cmake --build build/flavors/release -j
ctest --test-dir build/flavors/release --output-on-failure
```
> `build/` is a *container* for build trees — never configure straight into
> it. The layout convention is enforced by the build-tree guard at the top of
> [`CMakeLists.txt`](CMakeLists.txt); `python scripts/build.py` picks an
> isolated default directory for you.
> Test and HTTP builds use the pinned ForgeDeps package for verified dependency
> environments and external ForgeRecipes build recipes. Initialize a shared
> workspace with `python -m forgedeps init /path/to/deps`; offline builds reuse
> its verified sources and installed artifacts. No source is vendored.
### Portable build entry
`python scripts/build.py --test` configures, builds and runs host CTest. Select
`--platform qt|web|ios|android`; `--dry-run` prints the complete plan without
writing files. Default trees isolate platform, toolchain, configuration and
architecture. Use `--build-dir` for an existing cache and `--offline` for cached
dependencies. Android requires `--ndk`; iOS requires macOS/Xcode. Mobile tests
still use the existing device runners. Windows defaults to MSVC; MinGW is an
explicit separate cache. Ninja/MSVC requires a developer environment. Existing
SDK packaging and deployment scripts remain available.
On macOS, `--arch x86_64` / `--arch arm64` selects the actual target architecture.
Visual Studio accepts `--generator-platform x64` (or `ARM64`). Extra definitions
use `--cmake-arg=-DNAME[:TYPE]=VALUE` and cannot override the selected configuration
or toolchain. Compiler, toolchain and architecture cache conflicts are checked
before fetching dependencies; existing build directories are preserved.
Common invocations:
```bash
python3 scripts/build.py --test # release + ctest
python3 scripts/build.py --config Debug # debug
python3 scripts/build.py --config Debug --cmake-arg=-DARIA_ENABLE_ASAN=ON --cmake-arg=-DARIA_ENABLE_UBSAN=ON --test
python3 scripts/build.py --config Debug --cmake-arg=-DARIA_ENABLE_TSAN=ON --test
python3 scripts/build.py --toolchain msvc --test # Windows MSVC
python3 scripts/build.py --toolchain mingw --test # Windows MSYS2 UCRT64
```
### Windows toolchains
Aria supports **two parallel Windows toolchains** through the same portable
entry, each in its own isolated build tree.
| Toolchain | Command | Notes |
|---|---|---|
| **MSVC** (VS2026; VS2022 discovery retained) | `python scripts/build.py --toolchain msvc` | Default. Selects the Visual Studio generator matching the installation. |
| **MSYS2 UCRT64** (GCC 16+ / Clang 23+) | `python scripts/build.py --toolchain mingw` | Lightweight (~300 MB). Pre-installed on most CI images. Auto-detected from `C:\msys64\ucrt64\bin` and a few other common paths. |
You can switch back and forth without cleanup — the trees stay isolated.
CI validates both toolchains on pushes and pull requests.
#### MSVC one-time setup
```powershell
# 1. Install Visual Studio 2026 Build Tools (or the full IDE), CMake >= 4.2, and
# workload "Desktop development with C++" + "C++ CMake tools".
# 2. (Optional) install Qt 6 with the msvc2022_64 kit if you need the
# Qt6 adapter.
# 3. From a Developer PowerShell:
python scripts/build.py --toolchain msvc --test
```
#### MSYS2 one-time setup
```powershell
# 1. Install MSYS2 from https://www.msys2.org
# 2. Open the "MSYS2 UCRT64" shell:
pacman -Syu
pacman -S --needed mingw-w64-ucrt-x86_64-toolchain `
mingw-w64-ucrt-x86_64-cmake `
mingw-w64-ucrt-x86_64-ninja git
# 3. (Optional) Add C:\msys64\ucrt64\bin to your PATH.
# 4. From any shell:
python scripts/build.py --toolchain mingw --test
```
Rationale for shipping both: Aria uses C++ coroutines extensively that
libstdc++, libc++, **and** the MSVC STL all handle cleanly. Pinning a
single Windows toolchain artificially excluded a large chunk of users
in the .NET / Visual Studio ecosystem — we now validate against MSVC
v145 / VS2026 on the same release gate as macOS, Ubuntu, and MSYS2.
The `Visual Studio 18 2026` generator requires CMake >= 4.2. The automatic
build script retains discovery of existing VS2022 installations; current
MSVC release validation uses VS2026.
### Use it from your own project
**Option A — `find_package` after install** (recommended for production):
```bash
# In the aria tree:
python -m pip install -r requirements-build.txt
python -m forgedeps init /path/to/shared-dependencies
cmake -S . -B build/flavors/release -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local
cmake --build build/flavors/release -j && sudo cmake --install build/flavors/release
```
```cmake
# In your project's CMakeLists.txt:
find_package(aria 3.0 CONFIG REQUIRED)
add_executable(my_app main.cpp)
target_link_libraries(my_app PRIVATE aria::aria)
# or pick individual modules: aria::core / ::async / ::runtime / ::binding
```
Installed Linux shared libraries resolve other Aria libraries from their own
directory. Keep these libraries together; after moving the SDK, configure
consumers against its new installation path.
**Option B — separate source checkout (no install)**:
```cmake
set(ARIA_SOURCE_DIR "" CACHE PATH "Path to a separate Aria checkout")
add_subdirectory("${ARIA_SOURCE_DIR}" "${CMAKE_BINARY_DIR}/aria" EXCLUDE_FROM_ALL)
target_link_libraries(my_app PRIVATE aria::core aria::async)
```
Clone Aria separately outside your project, then pass its absolute path when configuring the application: `cmake -S . -B build -DARIA_SOURCE_DIR=/path/to/Aria`.
### Flagship example
[AriaTools](https://github.com/dqsjqian/AriaTools) is the single flagship cross-platform example, driving Qt, iOS, Android, and Web from one C++ ViewModel, with all four shells gated in CI. It is also the reference for both Android integration shapes: the Compose side-channel and the typed JniAdapter. The Aria repository no longer carries application examples. Framework behavior is pinned by `tests/acceptance/` and module tests, while these docs keep only focused, minimal snippets.
### Build options
| Option | Default | Description |
|--------|--------|-------------|
| `ARIA_BUILD_TESTS` | ON | Build unit tests + ctest registration. |
| `ARIA_BUILD_BENCHMARK` | ON | Build the micro-benchmark suite. |
| `ARIA_BUILD_SHARED` | ON | Runtime/binding as `.dylib`/`.so`/`.dll` instead of `.a`. |
| `ARIA_BUILD_QT6` | OFF | Build the Qt6 adapter (requires `Qt6Widgets`). |
| `ARIA_BUILD_APPKIT` | OFF | **(production-grade)** Build the macOS AppKit adapter as a first-class `STATIC` CMake module using Objective-C++; ships `aria::adapters::appkit` and passes the shared `adapter_conformance` battery. Requires `APPLE`. |
| `ARIA_BUILD_UIKIT` | OFF | **(production-grade)** Build the iOS UIKit adapter as a first-class `STATIC` CMake module using Objective-C++; ships `aria::adapters::uikit` and passes the shared conformance battery. Requires `APPLE`. |
| `ARIA_BUILD_JNI` | OFF | Build Android JNI adapter as a first-class CMake module — built as `STATIC`, ships `aria::adapters::jni`, implementing the same `IViewAdapter` contract as Qt/AppKit/UIKit via reflective JNI dispatch (text / bool / int / double / visibility / click). Requires an Android NDK toolchain (**NDK r30**, validated in CI for the C++23 core). |
| `ARIA_ENABLE_ASAN` | OFF | AddressSanitizer. |
| `ARIA_ENABLE_UBSAN` | OFF | UndefinedBehaviorSanitizer. |
| `ARIA_ENABLE_TSAN` | OFF | ThreadSanitizer. |
## 👋 Hello, world
The section above needs a UI adapter. To see the reactive core on its own, you need no UI
at all:
```cpp
#include "aria/aria.hpp"
using namespace aria;
Property count{0};
// No explicit dependency list — the first evaluation reads count, so
// count is recorded as a dependency automatically.
Computed label([&]{
return "count = " + std::to_string(count.get());
});
Command<> increment([&]{ count = count.get() + 1; });
// bind opens a subscription: it fires once immediately with the current
// value, then again on every change. The returned Subscription is the
// handle that OWNS that subscription's lifetime — so you must keep it.
// Write `label.bind(...);` and discard the result and the temporary dies
// on that very line, taking the subscription with it: nothing would ever
// print. (bind is [[nodiscard]], so the compiler warns you.)
auto sub = label.bind([](const std::string& s) { std::cout << s << '\n'; });
// ↑ this line has already printed "count = 0" (the initial sync)
increment(); // → "count = 1"
increment(); // → "count = 2"
// sub unsubscribes on destruction — no manual deregistration. You can
// also disconnect early:
sub.release();
increment(); // prints nothing
```
So `sub` exists to **express the subscription's lifetime as a scope**: while the variable
lives the subscription lives, and when it goes the subscription is torn down. In a real UI
this `Subscription` is usually a member of the View, so destroying the View detaches the
binding and no callback ever reaches a destroyed widget.
## ⚡ Async (C++ coroutines)
```cpp
#include "aria/async/task.hpp"
#include "aria/async/executor.hpp"
using namespace aria::async;
Task fetch_user(int id) {
co_await schedule_on(network_pool); // jump to worker thread
auto raw = http::get("/users/" + std::to_string(id));
co_await schedule_on(main_dispatcher); // jump back to UI thread
co_return parse(raw);
}
```
## 🌍 Cross-platform mapping
| Platform | UI host | Adapter |
|------------|----------------|------------------------------------|
| Windows | Qt6 | `aria-qt6` ✅ ready (MSYS2 UCRT64 + MSVC 2026) |
| macOS | AppKit / Qt6 | `aria-qt6` ✅ ready; AppKit ✅ ready |
| Linux | Qt6 | `aria-qt6` ✅ ready |
| iOS | UIKit | `aria-uikit` ✅ ready |
| Android | Compose / View | `aria-jni` ✅ ready (NDK r30) |
| **Web (server-driven)** | **HTML/JS in browser** | **`aria-http` ✅ ready (REST + SSE)** |
| Web (in-browser C++) | DOM via WASM | Not implemented; conditional roadmap work |
The HTTP adapter ships a small server (`HttpAdapter`) that exposes any
ViewModel over a JSON REST + Server-Sent-Events protocol, plus a
vanilla-JS browser SDK (`aria_client.js`). The server is built on the
coroutine-native **Mira** networking library (HTTP/1.1 + SSE) and
**nlohmann::json** (encode/decode). Dependencies default to the latest stable
release on first resolution and remain locked until explicitly updated;
explicit versions take precedence. CMake fetches checksum-verified archives
into the ignored build dependency cache; see [dependency versions](docs/dependencies.md).
aria itself owns the wire protocol, view registry, subscription dispatch
and SSE fan-out. It is the right shape for
desktop apps that want a web UI on the side, headless services, and
local debug dashboards. The WASM adapter — which compiles C++ business
logic into the browser sandbox — solves a different, more constrained
problem and remains conditional on a concrete consumer. See
[RFC 0001](docs/rfc/0001-http-adapter.md) for the design.
The **current release** ships the platform-agnostic core, runtime, async, and
binding layers — fully unit-tested. Qt6, AppKit, UIKit, JNI, and HTTP are
first-class opt-in adapters in the CMake tree (subject to their platform
requirements). WASM and SwiftUI remain conditional roadmap work.
## 🖼 Real-world showcase
The big picture first — three real applications grew out of one framework:

Below is what Aria looks like in real applications — one C++ ViewModel, native shells per
platform. **[AriaTools](https://github.com/dqsjqian/AriaTools)** (17-module cross-platform
workbench on Qt / iOS / Android / Web), **[AriaAgent](https://github.com/dqsjqian/AriaAgent)**
(provider-agnostic LLM Agent GUI), and [AriaRead](https://github.com/dqsjqian/AriaRead)
(cross-platform book-source engine, HTTP/SSE web shell) all run Aria 1.x in production
shape. Every screenshot comes from a stable release: one build, one shared C++ business
core across platforms.
### AriaTools — cross-platform workbench (17 modules)
Aria's flagship example: one ViewModel, four platforms. The cart / theme switching /
Framework Lab / Echo modules in the side navigation are all driven by `ObservableList`,
`Computed`, and `reactive::batch`.
| Platform | Screenshot | Adapter |
|---|---|---|
| macOS (Qt6) |  | `aria-qt6` |
| iOS / UIKit |  | `aria-uikit` |
| Android (Compose side-channel) |  | `aria-jni` |
| Web (HTTP/REST/SSE) |  | `aria-http` |
### AriaAgent — LLM Agent GUI
A provider-agnostic Agent GUI built on Aria + Qt6: true token-level streaming SSE,
tool-call chain visualization, permission approval (fail-closed), Markdown rendering.
| View | Screenshot |
|---|---|
| Main chat |  |
| Settings (General / Model / Plugins / Agent Presets) |  |
### AriaRead — cross-platform book-source engine
A book-source manager powered by the Aria HTTP adapter: source list on the left, book
cards on the right — search, subscribe, and debug in one place. The same C++ core drives
two web shapes: a REST+SSE thin client and an SSR variant.
| View | Screenshot |
|---|---|
| Source manager (Web, REST + SSE) |  |
| Source manager (Web, SSR) |  |
> These screenshots show the macOS example applications. Other platforms reuse
> the ViewModel; native appearance depends on the platform, Qt style, and host
> application. Consult CI for framework build and test results on Windows/Linux.
## 🧪 Test status
```bash
ctest --test-dir build/flavors/release --no-tests=error --output-on-failure
```
Tests exercise reactive state, collection events, async cancellation, binding
lifetimes, ABI, and adapter contracts. Enabled suites depend on platform and
build options. See [CI results](https://github.com/dqsjqian/Aria/actions/workflows/ci.yml),
[lifecycle contracts](docs/reference/lifecycle.md), and the
[error model](docs/reference/error-model.md).
## 📊 Benchmarks
Measured on 2026-09-13: Apple M3 Pro / Apple Clang 21 / C++20 Release
(`-O3 -DNDEBUG`). Each entry is the median of five paired runs' mean operation
times, comparing original revision `aa039f6` with 2.0 snapshot `2f22e17`.
| Operation | Original | Current |
|---|---:|---:|
| Property set, no observers | 20.5 ns | 13.2 ns |
| Property set, one observer | 98.9 ns | 35.0 ns |
| Computed chain ×5 | 570.8 ns | 229.0 ns |
| Ten sets in one batch | 250.6 ns | 102.5 ns |
| FilteredList tail append, 10k initial rows | 11.18 μs | 0.23 μs |
| SortedList random-key append, 10k initial rows | 8.38 μs | 17.28 μs |
Performance is mixed: owning event data and maintaining correct ordering after
batched changes also have costs. See the [performance reference](docs/reference/performance.md)
for all scenarios, complexity, remaining regressions, and reproduction details.
## 📋 Framework contracts
Every non-trivial behaviour Aria promises is pinned in a numbered
contract document. Each contract item carries an ID (e.g. `L-13`,
`E-22`, `LD-7`, `D-4`, `S-31`) so a failing assertion or PR review
comment can point straight at the canonical description.
| Document | Prefix | Scope |
|---|---|---|
| [`docs/reference/api-style.md`](docs/reference/api-style.md) | `S-N` | Naming, namespace, error and async-entry style |
| [`docs/reference/lifecycle.md`](docs/reference/lifecycle.md) | `L-N` | Threading, subscription, reactive flush, view-destroy, async cancel/dtor invariants |
| [`docs/reference/error-model.md`](docs/reference/error-model.md) | `E-N` | `aria::Error` / `ErrorKind` taxonomy and per-subsystem error contracts |
| [`docs/reference/list-diff-contract.md`](docs/reference/list-diff-contract.md) | `LD-N` | `Insert / Remove / Replace / Move / Reset / ItemChanged` semantics |
| [`docs/reference/diagnostics.md`](docs/reference/diagnostics.md) | `D-N` | `aria::TraceEvent` + `aria::TraceSink` protocol |
| [`docs/reference/performance.md`](docs/reference/performance.md) | `PERF-N` | Complexity bounds and per-operation baselines for every public API |
The P0 hard-bedrock pass (see CHANGELOG → *Latest framework-grade
hardening*) closed every open contract above; the seven
framework-level fuzzers in `modules/core/fuzz/` stress-verify the
lifecycle invariants (default 50k iterations / fuzzer; nightly runs
set `ARIA_FUZZ_ITERS=1000000`).
## 🗺 Capabilities
| Capability | Type | Where |
|---|---|---|
| Reactive state | `Property` / `Computed` / `Effect` | `aria/reactive/reactive.hpp` |
| Commands | `Command` (reactive `can_execute`) | `aria/command.hpp` |
| Collections | `ObservableList` + derived `Filtered/Sorted/Mapped/Distinct/Grouped/Paged` | `aria/observable_list.hpp`, `aria/derived/*` |
| Selection | `Selection` / `MultiSelection` (SE-1..SE-5) | `aria/selection.hpp` |
| Validation | `Validator` / `FormValidator` / `ValidationState` + async rules | `aria/validator.hpp`, `aria/binding/form.hpp`, `aria/async/async_validator.hpp` |
| Async | `Task` / `AsyncCommand` / `with_timeout` / `when_any` / `when_all` / `CancellationToken` | `aria/async/*` |
| Data fetching | `AsyncResource` (SWR + dedupe) / `Loadable` (5-state) | `aria/async/async_resource.hpp`, `aria/loadable.hpp` |
| Navigation | `Navigator` (`push`/`pop`/`push_for_result`, route patterns) | `aria/binding/navigation.hpp` |
| Binding | `BindingEngine` / `IViewAdapter` / `IView` / `Converter` / `bind_view_lifetime` | `aria/binding/*` |
| Diagnostics | `TraceEvent` / `TraceSink` / `GraphInspector` (atomic check when disabled) | `aria/diagnostics.hpp` |
**Learn it:** the [documentation index](docs/index.md) links the guides,
the [Cookbook](docs/cookbook/README.md) (task-oriented recipes), and the
contract references. The public [API reference](https://dqsjqian.github.io/Aria/)
is generated from main. See the [2.0 migration guide](docs/migration-2.0.md)
when upgrading from 1.2.x. Build the reference locally with
`cmake -B build/flavors/docs -DARIA_BUILD_DOCS=ON && cmake --build build/flavors/docs --target aria_docs`.
## 🗺 Roadmap
Aria is open source (MIT License), hosted on [GitHub](https://github.com/dqsjqian/Aria).
The [roadmap](docs/ROADMAP.md) defines development priorities, planned capabilities,
and explicitly deferred work. See the [changelog](CHANGELOG.md) for delivered capabilities and release history.
## 🤝 Contributing
Contributions are welcome! Please open an issue first to discuss design changes.
- Code style is enforced by `.clang-format` and `.clang-tidy`.
- All changes must pass `ctest --output-on-failure`.
- New features require tests in the matching `modules/*/tests/` suite.
## 🙏 Acknowledgments
- [doctest](https://github.com/doctest/doctest) — lightweight test framework
- [nlohmann_json](https://github.com/nlohmann/json) — JSON for Modern C++
- [Mira](https://github.com/dqsjqian/Mira) — coroutine-native C++23 networking (the HTTP adapter transport)
- [OpenSSL](https://www.openssl.org/) — TLS 1.2/1.3 (pinned release archives, verified by CMake)
## 📄 License
[MIT](LICENSE) © 2026 aria contributors
---
**📖 Other languages**
[简体中文](README.md)