Public alpha · MIT · built in Mojo

One framework for every app. Starting with data apps.

Write an app once in Mojo, as two functions. It runs natively, keeps the window live while the GPU does the heavy work, and every app is a set of tools agents can use.

Linux runsMac runs on CI MacsWeb runsAndroid emulatoriPhone builds
built with omxcode · Linux · 100 million rows

100 million rows, the window live. A median by region in 0.77 s on the GPU; the longest gap between frames meanwhile, 33 ms. One Mojo program, two functions.
↳ Linux · RTX 3090 · docs/goals/30-report.md

30msa filter change over 100M rows, from input to pixels on screenmedian · p95 49 ms vs Rust + Polars 131 ms · measured at 856a7e9, before the release build · docs/data-benchmark.md
17msthe longest gap between frames while a 1.5 s job ranexamples/jobwake on Linux · 90 frames during the job · docs/ui-threads.md
2–25×cheaper for an agent to see what changed: a call answers in words, 60–650 tokens, against ~1,600 for a screenshotMCP calls in omxplorer · a full screen read costs 2,800 · docs/agent.md
4.0scold start over 100M rows, the fastest of four buildsfile not cached · Rust + Polars 6.7 s · measured at 856a7e9, before the release build · docs/data-benchmark.md
The vision

One framework for everything. Data apps first.

A serious app today is four programs: an interface per platform, data work on a server, graphics in a shader language, and an API for agents. omxcode makes them one Mojo program. We start where that pays most: apps that move a lot of data between the screen and the GPU.

One way to do each thing

Every app is two functions.

view() describes the screen. update() reacts to a tap, a key or an agent's call. Less to learn, and less for an agent to get wrong.

viewdef view(self) -> View:
    return Button("Tapped " + String(self.n),
                  on_tap=TAP)
updatedef update(mut self, e: Event):
    if e.message == TAP:
        self.n += 1
MCP, built in

Every app is an MCP tool server.

Buttons, fields and JS widgets become tools, with no per-app work. A disabled button isn't a tool, so an agent can't do what a person couldn't.

Save→file-save Search…→search {text} Delete→no tool
a call60–650a screenshot~1,600

tokens for a call that answers in words; a full screen read is 2,800 · docs/agent.md

AG-UI, built in

Ask an agent. It answers with a screen.

Over AG-UI the reply is UI as data: native components, checked against the catalog before anything draws.

web and Linux · tested with the official AG-UI SDK

The window never waits

Slow work runs beside the screen.

update() only decides. Queries, video decoding and OCR run as jobs on their own threads and come back as events. A watchdog names any frame over budget.

UI thread
job thread
# slow work is a job; update() hears LANDED when it ends
self.running = start_ui_job(
    StepJob(self.orders.value(), self.filters))
def jobs_message(self) -> Int: return LANDED

# MOJOUI_BUDGET_MS=16: anything over budget is named
SLOW: update msg=7 80.06 ms

a 1.5 s job: 90 frames drawn meanwhile, longest gap 17 ms · examples/jobwake, Linux

Why omxcode exists

Four reasons.

1 · No boundary tax

No JSON, no HTTP, no second process.

Nothing extra to start, keep alive and debug. Apps that move a lot of data between the screen and the computing are faster and simpler.

2 · One language

From pixels to GPU kernels.

Mojo writes the interface and the CUDA-class kernels. In omxplorer, the group-by kernel sits in the same codebase as the sheet that shows its totals.

3 · Agent-driven

Every app can be driven by an agent.

omxcode has an agent host, so each app can be operated by an agent through the same code that draws its screens. JS apps need that built in separately.

4 · Every device

Native on every device from one codebase.

Phone included. Linux and the Mac run today; Android runs on the emulator and iPhone builds, with phones next on the roadmap.

Where to start, and where not yet

Start with apps that move a lot of data: analytics, spreadsheets, video, documents, robotics. For forms, CRUD screens and marketing sites, JS wins today on ecosystem alone; when a JS library is the better tool, embed it as a widget inside omxcode. SaaS building blocks (sign-in, accounts, payments) are on the roadmap.

Agents build screens · AG-UI

An agent answers with a screen. Drawn natively, never run as code.

An omxcode app speaks AG-UI, the open protocol between agents and apps. The agent sends a screen as data; the app checks it against a catalog of components and draws it with its own widgets. Early today; the catalog grows with every release.

Agent chat: asked for sales as a chart, an AG-UI agent answers with a card holding a chart, a Quarter/Year switch and a table
  • Speaks AG-UI. Reads streams recorded with the official AG-UI SDK, and every request it sends validates against the SDK's own models.
  • Safe by construction. No component an agent can name runs code or loads a page. Anything outside the catalog is refused, and the agent is told why.
  • Live and two-way. Fields and toggles edit state the agent shares; buttons send their answer back.

Agents can use today 13 components

CardVStackHStackDividerTextParagraphTableSparklineMeterButtonTextFieldToggleSegmented

Next planned

Proved against a scripted AG-UI agent built on the official SDK. Not yet tested against other AG-UI frameworks or recorded with a live model. docs/agui.md

How it works

One program. The window never waits.

Press Play to follow a tap, or click any block to read what it does.

Open full screen ›

One app.mojo, one process: native screens on each platform, MCP tools and AG-UI screens for agents, jobs and the GPU underneath.

Components

Building blocks, each one tested.

What each family solves, and where a script runs it today. Generated from the code and the checks.

121components

117 run on Linux and the web under a script on every check. The bars: tested, then builds.

Linux118 / 121
Web117 / 121
Mac0 / 121
Android16 / 121
iPhone0 / 121
Agents55 / 121

Mac apps run on GitHub's macOS runners (scripts/mac-ci); checking each component there is next.

Browse all 121

generated by scripts/site_components.py from docs/components.json and docs/components.md

Measured one RTX 3090

Numbers, with where they came from.

Each build written from its own stack's docs, run by the same script on the same machine. Lower is better.

A change over 100M rowsinput to pixels · median ms

JS + DuckDB-WASM104.9
JS + Python Polars44.2
Rust + Polars37.0
omxcode30.3

32 filter changes × 3 runs, at commit 856a7e9; the release build re-checked only at 10M · docs/data-benchmark.md

The slowest 5 % of changesinput to pixels · p95 ms

JS + DuckDB-WASM285.5
JS + Python Polars138.3
Rust + Polars130.7
omxcode49.1

every build matched DuckDB's answers · docs/data-benchmark.md

A frame at 20M particleson screen · mean ms

Plain JS217.7
JS + Rust/wasm53.45
JS + WebGPU3.01
omxcode3.13

WebGPU wins by 4 % · native Rust, offscreen only here: 5.99 · why.html

Where others win: Rust + Polars uses less memory at 100M rows (3.6 GB, no GPU; omxcode 5.6 GB plus 5.7 GB on the GPU) · native Rust starts the particle field in 211 ms · these numbers need an NVIDIA GPU (omxplorer also runs its queries on Apple's Metal).

Build your own

Write your own app.

Free and open source, MIT. Linux with an NVIDIA GPU for now. Just want to play? Download omxplorer.

Start here Linux

Clone it, install Mojo and the rest with pixi, and build the smallest app: one file, examples/hello/app.mojo, two functions.

git clone https://github.com/abhisheksreesaila/omxcode
cd omxcode && pixi install
scripts/build.sh hello linux
build/hello/linux/hello

x86-64 Linux, GTK 4 and libadwaita 1.7+ · copy examples/hello to start your own · How it works · Components · llms.txt for agents