Native Shell (NSH)
AI-generated UI, native in your app. Native Shell renders UI written in TSX and Tailwind with each platform's own UI: native views on iOS, Android, macOS, Windows and Linux, GPUI in GPUI apps and HTML on the web. Apps load these modules at run time, as plugins: written by a model or by your team, delivered as signed packages and run in a sandbox the host configures. The same module can also be a standalone app.
import { mount, signal, Text, View } from "nsh"; function App() { const count = signal(0); return ( <View class="flex-1 items-center justify-center gap-4 bg-white dark:bg-zinc-900"> <Text class="text-3xl font-semibold text-zinc-900 dark:text-white">{count()}</Text> <View class="rounded-xl bg-blue-600 px-5 py-3 active:opacity-60" onPress={() => count.update((c) => c + 1)}> <Text class="text-white">Tap</Text> </View> </View> ); } mount(App);
Documentation, guides and live demos: nsh.dev.
Features
- Real native UI. Every element is a platform view (UIKit, Android views, AppKit, Win32 drawn with Direct2D, GTK 4), a GPUI element or HTML, laid out with flexbox and grid (Taffy). The system's text, input, scrolling and accessibility just work, and native components such as maps and web views layer naturally with NSH's views.
- Plugins, or standalone apps. Put an
NshAppView(iOS),NshView(Android) orAppView(desktop and GPUI) on any screen of an existing app, orcreatePlayerin a web page, and load modules into it at run time, from a bundle, the dev server or a downloaded signed package: features ship on your own schedule, next to the host's own native components. The same module also packages into an installable iOS, Android, macOS, Windows, Linux or GPUI app, or a static website, with onensh packagecommand. - AI-friendly: TSX + Tailwind. A module is one TSX file of components, signals and Tailwind classes, the format models
write best. Every element, prop and module has TypeScript declarations generated from the Rust sources, the docs are
served to models as llms.txt, and
nsh traceruns a module headless to check it without a device. - Sandboxed and signed. Each view runs its module in its own QuickJS VM, with memory, call-time and node limits, reaching only the capabilities the host grants. Packages are signed with Ed25519 by release keys an offline root certifies, and the device checks a revocation list.
- Fast, all in Rust. Only the app's code is JavaScript: signals, the renderer, layout, animation and every
module apps import are Rust, and each frame crosses to the UI thread as one batch. The single
nshbinary bundles, type-checks, serves hot reload and packages: it is the whole toolchain module authors need.
| Platform | Drawn with | Embed with | Requires |
|---|---|---|---|
| iOS | UIKit, CoreText | NshAppView (Swift, NativeShell.xcframework) |
iOS 15+ |
| Android | Android views, StaticLayout |
NshView (Java / Kotlin, nsh.aar) |
Android 9 (API 28)+ |
| macOS | AppKit, Core Animation, CoreText | AppView (Rust, nsh-platform-macos) |
macOS 14+ |
| Windows | Win32, Direct2D, DirectWrite | AppView (Rust, nsh-platform-windows) |
Windows 10 1809+ |
| Linux | GTK 4, Pango | AppView (Rust, nsh-platform-linux) |
GTK 4.14+ |
| GPUI (macOS, Windows, Linux) | GPUI (GPUI Fast) | AppView (Rust, a GPUI view, nsh-platform-gpui) |
macOS, Windows; Linux with Vulkan |
| Web | HTML, CSS | createPlayer (JavaScript) or an iframe |
Modern browsers |
The GPUI backend (nsh run --target gpui, nsh package --target gpui) draws apps with GPUI on all three desktops and
embeds in GPUI and GPUI Kit apps. The web platform (nsh run --target web, nsh package --target web) publishes apps
as static sites and runs the website's live demos.
Quick start
Install the nsh command (other ways):
curl -fsSL https://nsh.dev/install.sh | sh # macOS, Linux irm https://nsh.dev/install.ps1 | iex # Windows (PowerShell) brew install longbridge/tap/nsh # Homebrew
Create an app and run it with hot reload:
nsh init my-app nsh run my-app # a window on this machine (on macOS, an iPhone-sized Mac Catalyst window) nsh run my-app --target ios # iOS simulator (needs Xcode) nsh run my-app --target android # Android emulator or device (needs the Android SDK) nsh run my-app --target macos # an AppKit window nsh run my-app --target gpui # a GPUI window (macOS, Windows, Linux) nsh run my-app --target web # in the browser
nsh init writes App.tsx, nsh.json and a tsconfig.json, and keeps type declarations in .nsh/types, so any
TypeScript editor checks the app on its own. On every save only the edited components render again; the
rest of the app keeps its state. Logs and errors show in the terminal. What each platform needs:
Installation.
Embed it in your app
iOS (Swift):
import NativeShell let app = NshAppView() view.addSubview(app) // constrain it like any view #if DEBUG try app.connectDevServer(URL(string: "ws://127.0.0.1:8790/ws")!) // `nsh dev my-app` #else try app.loadBundle(at: Bundle.main.url(forResource: "bundle", withExtension: "qbc", subdirectory: "nsh")!) #endif
Android (Kotlin):
val nsh = NshView(this) setContentView(nsh) // or add it to any layout if (BuildConfig.DEBUG) nsh.connectDevServer("ws://127.0.0.1:8790/ws") else nsh.loadAssetBundle("nsh")
nsh build my-app --release writes the bundle a release build loads. More:
iOS, Android,
desktops, native components,
sandbox and capabilities.
Ship updates
nsh keygen keys/root && nsh keygen keys/release # a root key kept offline, and a release key nsh certify --root keys/root.secret --key keys/release.pub --apps 'com.example.*' -o keys/release.cert nsh publish my-app --key keys/release.secret --cert keys/release.cert --build 2 # a signed .nshpkg
The app trusts the root's public key and loads what it downloads with loadPackage
(Signed packages). To ship the module as an app of its own instead:
nsh package my-app --target ios-simulator --run # also ios, android, macos, windows, linux, gpui, webExamples
| Example | What it shows |
|---|---|
examples/gallery |
A tour of what NSH supports: lists, navigation, forms, controls, gestures, animation, images, styles, text, web view and video, fetch |
examples/counter |
The smallest app |
examples/hopper |
A dark, tabbed dashboard built only from primitives: interactive canvas charts, sliders, menus, animation |
examples/desktop |
A desktop app with a title bar and menus of its own (nsh/desktop) |
examples/gallery-rs |
The gallery with its own components written in Rust |
examples/embed-ios, examples/embed-android |
NSH inside existing native apps, with a native component the app registers |
examples/bench |
Rust components against the same components in TSX |
nsh run examples/gallery
Building from source
With Rust (rustup; rust-toolchain.toml picks the toolchain):
git clone https://github.com/longbridge/nsh.git && cd nsh cargo run # the gallery on this machine's backend, with hot reload cargo run -- examples/counter # another app cargo run -- --target ios # or catalyst, android cargo xtask dist # the distribution (CLI, runtimes, SDKs) in dist/nsh
Installation lists the hosts and runtimes each target needs.
Contributing
CONTRIBUTING.md covers pull requests, commits and testing; AGENTS.md the commands, rules and conventions; docs/dev the architecture and internals. The website's sources are in website/.
GPUI Kit is a sibling project: components and tools for desktop apps built with GPUI. NSH's theme colors follow its fields, and NSH's GPUI backend builds on it.
License
Licensed under the Apache License, Version 2.0.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache-2.0 license, shall be licensed under Apache-2.0, without any additional terms or conditions.