robius-app-architecture – skill Lập trình cho agent AI
CRITICAL: Dùng cho các mẫu kiến trúc ứng dụng Robius. Kích hoạt khi có: Tokio, async, submit_async_request, 异步, 架构, SignalToUI, Cx::post_action, worker task, app structure, MatchEvent, handle_startup
Cài skill robius-app-architecture bằng một lệnh
Chọn công cụ bạn đang dùng, copy lệnh và dán vào terminal. Skill sẽ nằm trong thư mục skills của công cụ đó và sẵn sàng dùng ở phiên làm việc tiếp theo.
Claude Code
mkdir -p ~/.claude/skills && curl -fsSL https://skill.dn1nguoi.com/z/robius-app-architecture-47489.tgz | tar xz -C ~/.claude/skills
Gọi trong Claude Code: /robius-app-architecture – rồi mô tả công việc bạn muốn làm.
Codex
mkdir -p ~/.codex/skills && curl -fsSL https://skill.dn1nguoi.com/z/robius-app-architecture-47489.tgz | tar xz -C ~/.codex/skills
Gọi trong Codex: $robius-app-architecture – rồi mô tả công việc bạn muốn làm.
Hermes Agent
mkdir -p ~/.hermes/skills && curl -fsSL https://skill.dn1nguoi.com/z/robius-app-architecture-47489.tgz | tar xz -C ~/.hermes/skills
Gọi trong Hermes Agent: /robius-app-architecture – rồi mô tả công việc bạn muốn làm.
DeepSeek
mkdir -p ~/.deepcode/skills && curl -fsSL https://skill.dn1nguoi.com/z/robius-app-architecture-47489.tgz | tar xz -C ~/.deepcode/skills
Gọi trong DeepSeek: /robius-app-architecture – rồi mô tả công việc bạn muốn làm.
Nội dung SKILL.md
Nội dung SKILL.md gốc bằng tiếng Anh.
Supporting material availability
This catalog copy contains the inline guidance below, but does not include the following supporting paths. They are external prerequisites, not bundled files:
<support-root>/references/tokio-integration.md<support-root>/references/channel-patterns.md<support-root>/references/moly-async-patterns.md
Ask for the original supporting material or an existing installation before using a step that depends on these paths; this catalog does not identify a verified download source for them. Resolve each path relative to that installation, inspect its contents, and verify any applicable license and execution prerequisites. Do not run a command or claim a referenced procedure was followed until its required file exists. Do not fabricate the missing scripts or treat an unrelated file with the same name as equivalent. Independent steps fully documented here can proceed within the user’s authorized scope; report any dependent step as unavailable.
Robius App Architecture Skill
Best practices for structuring Makepad applications based on the Robrix and Moly codebases - production applications built with Makepad and Robius framework.
Source codebases:
- Robrix: Matrix chat client - complex sync/async with background subscriptions
- Moly: AI chat application - cross-platform (native + WASM) with streaming APIs
When to Use
Use this skill when:
- Building a Makepad application with async backend integration
- Designing sync/async communication patterns in Makepad
- Structuring a Robius-style application
- Keywords: robrix, robius, makepad app structure, async makepad, tokio makepad
Production Patterns
The upstream _base/ directory is not bundled; these are historical pattern names, not production-certified implementations:
| Pattern | Description |
|---------|-------------|
| 08-async-loading | Async data loading with loading states |
| 09-streaming-results | Incremental results with SignalToUI |
| 13-tokio-integration | Full tokio runtime integration |
Core Architecture Pattern
┌─────────────────────────────────────────────────────────────┐
│ UI Thread (Makepad) │
│ ┌─────────┐ ┌──────────┐ ┌──────────────────────┐ │
│ │ App │────▶│ WidgetRef │────▶│ Widget Tree (View) │ │
│ │ State │ │ ui │ │ Scope::with_data() │ │
│ └────┬────┘ └──────────┘ └──────────────────────┘ │
│ │ │
│ │ submit_async_request() │
│ ▼ │
│ ┌─────────────────┐ ┌─────────────────────────┐ │
│ │ REQUEST_SENDER │─────────▶│ Crossbeam SegQueue │ │
│ │ (MPSC Channel) │ │ (Lock-free Updates) │ │
│ └─────────────────┘ └─────────────────────────┘ │
└───────────────────────────────────┬─────────────────────────┘
│
SignalToUI::set_ui_signal()
│
┌───────────────────────────────────┴─────────────────────────┐
│ Tokio Runtime (Async) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ worker_task (Request Handler) │ │
│ │ - Receives Request from UI │ │
│ │ - Spawns async tasks per request │ │
│ │ - Posts actions back via Cx::post_action() │ │
│ └──────────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Per-Item Subscriber Tasks │ │
│ │ - Listens to external data stream │ │
│ │ - Sends Update via crossbeam channel │ │
│ │ - Calls SignalToUI::set_ui_signal() to wake UI │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘App Structure
Top-Level App Definition
use makepad_widgets::*;
live_design! {
use link::theme::*;
use link::widgets::*;
App = {{App}} {
ui: <Root>{
main_window = <Window> {
window: {inner_size: vec2(1280, 800), title: "MyApp"},
body = {
// Main content here
}
}
}
}
}
app_main!(App);
#[derive(Live)]
pub struct App {
#[live] ui: WidgetRef,
#[rust] app_state: AppState,
}
impl LiveRegister for App {
fn live_register(cx: &mut Cx) {
// Order matters: register base widgets first
makepad_widgets::live_design(cx);
// Then shared/common widgets
crate::shared::live_design(cx);
// Then feature modules
crate::home::live_design(cx);
}
}
impl LiveHook for App {
fn after_new_from_doc(&mut self, cx: &mut Cx) {
// One-time initialization after widget tree is created
}
}AppMain Implementation
impl AppMain for App {
fn handle_event(&mut self, cx: &mut Cx, event: &Event) {
// Forward to MatchEvent trait
self.match_event(cx, event);
// Pass AppState through widget tree via Scope
let scope = &mut Scope::with_data(&mut self.app_state);
self.ui.handle_event(cx, event, scope);
}
}Tokio Runtime Integration
Static Runtime Initialization
use std::sync::Mutex;
use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
static TOKIO_RUNTIME: Mutex<Option<tokio::runtime::Runtime>> = Mutex::new(None);
static REQUEST_SENDER: Mutex<Option<UnboundedSender<AppRequest>>> = Mutex::new(None);
pub fn start_async_runtime() -> Result<tokio::runtime::Handle> {
let (request_sender, request_receiver) = tokio::sync::mpsc::unbounded_channel();
let rt_handle = TOKIO_RUNTIME.lock().unwrap()
.get_or_insert_with(|| {
tokio::runtime::Runtime::new()
.expect("Failed to create Tokio runtime")
})
.handle()
.clone();
// Store sender for UI thread to use
*REQUEST_SENDER.lock().unwrap() = Some(request_sender);
// Spawn the main worker task
rt_handle.spawn(worker_task(request_receiver));
Ok(rt_handle)
}Request Submission Pattern
pub enum AppRequest {
FetchData { id: String },
SendMessage { content: String },
// ... other request types
}
/// Submit a request from UI thread to async runtime
pub fn submit_async_request(req: AppRequest) -> std::result::Result<(), AppRequest> {
if let Some(sender) = REQUEST_SENDER.lock().unwrap().as_ref() {
sender.send(req).map_err(|error| error.0)
} else {
Err(req) // report unavailable runtime rather than silently dropping work
}
}Worker Task Pattern
async fn worker_task(mut request_receiver: UnboundedReceiver<AppRequest>) -> Result<()> {
while let Some(request) = request_receiver.recv().await {
match request {
AppRequest::FetchData { id } => {
// Spawn a new task for each request
let _task = tokio::spawn(async move {
let result = fetch_data(&id).await;
// Post result back to UI thread
Cx::post_action(DataFetchedAction { id, result });
});
}
AppRequest::SendMessage { content } => {
let _task = tokio::spawn(async move {
match send_message(&content).await {
Ok(()) => Cx::post_action(MessageSentAction::Success),
Err(e) => Cx::post_action(MessageSentAction::Failed(e)),
}
});
}
}
}
Ok(())
}Lock-Free Update Queue Pattern
For high-frequency updates from background tasks:
use crossbeam_queue::SegQueue;
use makepad_widgets::SignalToUI;
pub enum DataUpdate {
NewItem { item: Item },
ItemChanged { id: String, changes: Changes },
Status { message: String },
}
static PENDING_UPDATES: SegQueue<DataUpdate> = SegQueue::new();
/// Called from background async tasks
pub fn enqueue_update(update: DataUpdate) {
PENDING_UPDATES.push(update);
SignalToUI::set_ui_signal(); // Wake UI thread
}
// In widget's handle_event:
impl Widget for MyWidget {
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
// Poll for updates on Signal events
if let Event::Signal = event {
while let Some(update) = PENDING_UPDATES.pop() {
match update {
DataUpdate::NewItem { item } => {
self.items.push(item);
self.redraw(cx);
}
// ... handle other updates
}
}
}
}
}Start
… (nội dung đầy đủ có trong gói tải về)
Skill liên quan
- robius-matrix-integration – CRITICAL: Dùng để tích hợp Matrix SDK với Makepad. Kích hoạt khi có: Matrix SDK, sliding…
- robot-framework-skill – Tạo test Robot Framework theo cú pháp keyword-driven bằng Python. Hỗ trợ…
- robots-txt-validator – Robots.txt Validator. Dùng khi làm việc với nội dung robots.txt, crawler và URL cần kiểm…
- ruby – Hướng dẫn mã nguồn chuyên sâu theo ngôn ngữ cho Ruby.
- ruby-pro – Viết mã Ruby đúng chuẩn idiom với metaprogramming, mẫu Rails và tối ưu hiệu năng. Chuyên…
- runapi-cli – Tạo ảnh, video và nhạc/âm thanh bằng AI từ agent sử dụng RunAPI CLI.
- rust – Hướng dẫn mã nguồn chuyên sâu theo ngôn ngữ cho Rust.
- rust-async-patterns – Làm chủ lập trình bất đồng bộ trong Rust với Tokio, async trait, xử lý lỗi và các mẫu…