Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Technology Philosophy: Rust + WebAssembly Only

Core Principle

robit is a Rust project. Full stop.

We will not use:

  • ❌ TypeScript/JavaScript frontend frameworks (React, Vue, Angular, Lit)
  • ❌ Node.js/npm ecosystem for UI
  • ❌ Separate language for web vs terminal
  • ❌ JavaScript bundlers (webpack, vite, rollup)

We will use:

  • Rust for all logic and UI
  • WebAssembly for browser deployment
  • ratatui for terminal UI
  • ratzilla for web UI (terminal aesthetic in browser)
  • Leptos (optional future) for rich web UI if needed
  • trunk for WASM builds
  • Cargo for everything

Why This Matters

Type Safety

Rust’s type system catches errors at compile time:

#![allow(unused)]
fn main() {
// This won't compile - the compiler catches it
let conversation: Conversation = load_conversation(id)?;
// conversation is guaranteed to be valid here
}

Compare to TypeScript:

// This might fail at runtime despite types
const conversation = await loadConversation(id);
// conversation might be null, undefined, or malformed

Single Toolchain

Rust approach:

cargo build          # Build everything
cargo test           # Test everything
cargo clippy         # Lint everything
cargo doc            # Document everything

TypeScript approach (pi-mono):

npm install          # Node dependencies
npm run build        # Compile TypeScript
npm run check        # Lint + format
tsc --noEmit         # Type check

Performance

  • Zero-cost abstractions: What you write is what runs
  • No garbage collection: Predictable performance
  • WASM is fast: Near-native speed in browser
  • Small bundles: Rust WASM is typically smaller than JS bundles

The WebAssembly Path

Phase 1: Terminal-First (Current)

┌─────────────────────────────────────┐
│  robit (ratatui + crossterm)  │
│                                     │
│  Native terminal, full experience   │
└─────────────────────────────────────┘

Deploy: cargo install robit

Phase 2: Web Convenience

┌─────────────────────────────────────┐
│  robit-web (ratatui + ratzilla)│
│                                     │
│  Same UI code, renders to DOM       │
│  Terminal aesthetic in browser      │
└─────────────────────────────────────┘

Deploy: Static hosting (GitHub Pages, Netlify, etc.)

Phase 3: Rich Web (If Needed)

┌─────────────────────────────────────┐
│  robit-web-rich (Leptos)      │
│                                     │
│  Full web framework (still Rust!)   │
│  Rich interactions, modern UX       │
└─────────────────────────────────────┘

Deploy: Static hosting or serverless functions

Why Leptos?

  • Full-stack Rust framework
  • Compiles to WASM
  • Reactive like React, but Rust-native
  • No JavaScript required
  • Can reuse robit-core crate
#![allow(unused)]
fn main() {
// Leptos example - still Rust!
#[component]
fn ConversationView() -> impl IntoView {
    let (messages, set_messages) = create_signal(vec![]);
    
    view! {
        <div class="conversation">
            <For
                each=messages
                key=|msg| msg.id
                children=|msg| view! { <Message msg=msg /> }
            />
        </div>
    }
}
}

Common Objections

“But JavaScript has better web ecosystem!”

Reality: The WASM ecosystem has matured:

  • trunk: Like webpack but for Rust WASM
  • web-sys: Complete browser API bindings
  • gloo: Ergonomic wrappers for web APIs
  • Leptos/Dioxus/Yew: Full React-like frameworks in Rust

“TypeScript has good types too!”

Reality: TypeScript’s type system is unsound:

// Valid TypeScript that crashes at runtime
const x: number = "hello" as any;
console.log(x + 1); // NaN or "hello1"

Rust’s type system is sound and enforced at compile time.

“JavaScript is easier to hire for!”

Reality: This is a passion project, not enterprise software. We optimize for:

  • Developer experience (ourselves)
  • Code quality
  • Long-term maintainability

Not hiring metrics.

“But pi-mono is successful with TypeScript!”

Reality: Different projects, different goals. pi-mono optimizes for:

  • Ease of contribution (11k stars, 117 contributors)
  • Familiar stack (JavaScript/TypeScript is popular)
  • Rich web features (they need them)

We optimize for:

  • Type safety
  • Performance
  • Single ecosystem
  • Terminal-first experience

Both can be successful.

The Escape Hatch

If we discover that the terminal aesthetic in browser is too limiting, and ratzilla can’t be extended enough:

Option A: Build a Leptos app

  • Still Rust
  • Still WASM
  • Rich web UI
  • Reuse robit-core

Option B: Enhance ratzilla

  • Add custom DOM elements for rich features
  • Keep terminal aesthetic for chat
  • Add file previews, drag-drop as needed

Option C (not happening): Use React/Vue

  • ❌ Not in this codebase
  • ❌ Different language
  • ❌ Different toolchain
  • ❌ Different mental model

Examples in the Wild

Other projects successfully using Rust + WASM for web:

  • Figma: Rust core, WASM in browser
  • Ruffle: Flash emulator in Rust/WASM
  • WordPress Playground: PHP in WASM (Rust toolchain)
  • Ratzilla demos: Terminal UIs in browser
  • Leptos apps: Full web apps in Rust

The approach is proven.

Our Stack

Language:       Rust (100%)
Terminal UI:    ratatui + crossterm
Web UI:         ratatui + ratzilla (WASM)
Future web:     Leptos (if needed, still Rust)
Build tool:     Cargo + trunk
Package mgr:    Cargo
Testing:        Built-in (cargo test)
Linting:        Clippy
Formatting:     rustfmt

No npm. No node_modules. No package.json. No webpack config.

Just Rust.

Conclusion

This isn’t about hating JavaScript or TypeScript. They’re fine tools for many projects.

This is about choosing the right tool for our specific project:

  • A terminal-first LLM tool
  • Where type safety matters (AI interactions)
  • Where performance matters (streaming responses)
  • Where we want a single, cohesive codebase

Rust + WebAssembly is that tool.