umo
Universal Modules — Write once, import anywhere. (A Claude Experiment)
umo compiles packages from any language into universal WebAssembly modules that can be imported natively by any other language.
Python package ──┐
│
Go module ───┼──► WASM Component ──► Import from Node, Python, Go, Rust...
│
npm package ───┘
Why umo?
Each programming language ecosystem has many useful libraries. Umo makes them available to every language.
Quick Start
Install a Python package for use in Node.js
# Install the humanize package as a universal module umo pip-install humanize # That's it. Now use it in JavaScript:
import { intcomma, naturalsize, ordinal } from './umo_modules/humanize/index.js'; console.log(intcomma(1000000)); // "1,000,000" console.log(naturalsize(3000000)); // "3.0 MB" console.log(ordinal(42)); // "42nd"
Full TypeScript support included — autocomplete, type checking, everything just works.
Use Python classes with persistent state
Python:
from redblacktree import rbtree tree = rbtree() tree.insert(5, 'five') tree.insert(3, 'three') tree.insert(7, 'seven') print(tree.depth()) # 2 print(list(tree.inorder())) # [(3, 'three'), (5, 'five'), (7, 'seven')]
Node.js (same types, same API):
import { Rbtree } from './umo_modules/redblacktree/index.js'; const tree = new Rbtree([]); tree.insert(5, 'five'); tree.insert(3, 'three'); tree.insert(7, 'seven'); console.log(tree.depth()); // 2 console.log(tree.inorder()); // [[3,"three"],[5,"five"],[7,"seven"]]
Types map directly: Python int → JS number, Python list → JS array. State persists across calls.
Installation
Prerequisites
umo requires these tools (installed automatically or via your package manager):
| Tool | Purpose | Install |
|---|---|---|
| Node.js 18+ | Runtime | nodejs.org |
| Python 3.11+ | Python compilation | python.org |
| componentize-py | Python → WASM | pip install componentize-py |
Commands
umo pip-install <package>
Install a Python package as a universal module.
# Install latest version umo pip-install humanize # Install specific version umo pip-install humanize@4.15.0
Output: Creates umo_modules/<package>/ with:
index.js— JavaScript bindingsindex.d.ts— TypeScript declarationsbindings/— WASM component and runtime
umo pip-list
List available curated packages.
How It Works
┌─────────────────┐
│ Python Package │
│ (humanize) │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Type Extraction │ Analyzes signatures, docstrings, type hints
└────────┬────────┘
│
▼
┌─────────────────┐
│ WIT Generation │ Creates WebAssembly Interface Types
└────────┬────────┘
│
▼
┌─────────────────┐
│ componentize │ Compiles Python + CPython to WASM
└────────┬────────┘
│
▼
┌─────────────────┐
│ jco transpile │ Generates JS bindings from WASM
└────────┬────────┘
│
▼
┌─────────────────┐
│ umo_modules/ │ Ready to import!
│ humanize/ │
└─────────────────┘
Implementation: umo uses the WebAssembly Component Model to create portable, typed interfaces between languages. Functions calls cross the language boundary with native performance — no JSON serialization, no HTTP overhead.
Supported Languages
Source Languages (compile from)
| Language | Status | Command |
|---|---|---|
| Python | Stable | umo pip-install <pkg> |
| TypeScript | Planned | umo npm-install <pkg> |
| Go | Planned | umo go-install <pkg> |
| Rust | Planned | umo cargo-install <pkg> |
Target Languages (import into)
| Language | Status |
|---|---|
| JavaScript/TypeScript | Stable |
| Python | Planned |
| Go | Planned |
| Rust | Planned |
Examples
Number Formatting
import { intcomma, intword, ordinal, apnumber, scientific, metric } from './umo_modules/humanize/index.js'; intcomma(1234567); // "1,234,567" intword(1200000000); // "1.2 billion" ordinal(3); // "3rd" apnumber(5); // "five" scientific(0.00042, 2); // "4.20 x 10⁻⁴" metric(1500, "V", 3); // "1.50 kV"
File Sizes
import { naturalsize } from './umo_modules/humanize/index.js'; naturalsize(300); // "300 Bytes" naturalsize(3000); // "3.0 kB" naturalsize(3000000); // "3.0 MB" naturalsize(3000000000); // "3.0 GB"
Data Structures
import { Rbtree } from './umo_modules/redblacktree/index.js'; // Create a red-black tree (self-balancing BST) const tree = new Rbtree([]); // Stateful operations tree.insert(10, 'ten'); tree.insert(5, 'five'); tree.insert(15, 'fifteen'); // Query - returns native JS types console.log(tree.depth()); // 2 (number) console.log(tree.inorder()); // [[5,"five"],[10,"ten"],[15,"fifteen"]]
Data Science with Pandas
import * as pd from './umo_modules/pandas/index.js'; // Create DataFrames const df1 = await pd.DataFrame.create({ 'A': [1, 2], 'B': [3, 4] }); const df2 = await pd.DataFrame.create({ 'A': [5, 6], 'B': [7, 8] }); // Concatenate const combined = await pd.concat([df1, df2]); // Merge DataFrames const left = await pd.DataFrame.create({ key: ['A', 'B'], val: [1, 2] }); const right = await pd.DataFrame.create({ key: ['A', 'C'], val: [3, 4] }); const merged = await pd.merge(left, right, 'inner', 'key'); // Check for missing values console.log(await pd.isna(null)); // true
Type Safety
umo generates full TypeScript declarations from Python type hints:
// Auto-generated index.d.ts export function intcomma(value: number, ndigits?: number): string; export function naturalsize(value: number, binary?: boolean, gnu?: boolean): string; export function ordinal(value: number): string; export class Rbtree { constructor(initial: any[]); insert(key: number, value: string): void; remove(key: number): void; depth(): number; inorder(): Array<[number, string]>; }
Your editor provides autocomplete, parameter hints, and type checking — just like native packages.
Validated Packages
umo has been tested with 30+ Python packages across different categories. Here's a sample:
| Package | Category | Description |
|---|---|---|
pandas |
Data Science | DataFrames, data analysis (via Pyodide) |
networkx |
Data Science | Graph/network analysis (via Pyodide) |
sqlalchemy |
Database | SQL toolkit and ORM |
flask |
Web | Web microframework |
jinja2 |
Templating | Template engine |
beautifulsoup4 |
Parsing | HTML/XML parsing |
humanize |
Formatting | Human-readable numbers, dates, sizes |
click |
CLI | Command-line interface framework |
arrow |
Date/Time | Date and time handling |
redblacktree |
Data Structures | Self-balancing binary search tree |
View full list of validated packages — includes 30+ packages across web, data, CLI, utilities, and more.
Note: We validate that packages compile and run with basic tests. We don't maintain full test suite translations from the original Python packages.
Limitations
Current Limitations
- Python stdlib: Some stdlib modules aren't available in WASM (e.g.,
_ssl,mmap) - Native extensions: Some packages with C/Rust extensions require Pyodide runtime (pandas, networkx, numpy work; requests, pydantic don't)
- File I/O: Limited filesystem access in WASM sandbox
- Networking: No direct network access from WASM
Coming Later
- Go module compilation
- TypeScript/npm package compilation
- Import WASM modules into Python
- Import WASM modules into Go
- Browser support (run Python packages client-side)
- Package registry for pre-compiled modules
Architecture
umo/
├── src/
│ ├── cli.ts # CLI entry point
│ ├── pip/
│ │ ├── package-resolver.ts # pip package resolution
│ │ ├── type-extractor.ts # Python type analysis
│ │ ├── wit-generator.ts # WIT interface generation
│ │ ├── wasm-compiler.ts # componentize-py integration
│ │ ├── js-generator.ts # JavaScript binding generation
│ │ └── dts-generator.ts # TypeScript declaration generation
│ ├── compiler/ # WASM compilation utilities
│ └── utils/ # Shared utilities
├── umo_modules/ # Compiled universal modules
└── tests/ # Test suite
Development
# Clone and install git clone https://github.com/AlaShiban/umo cd umo npm install # Build npm run build # Run tests npm test # Development mode npm run dev
FAQ
Q: How big are the compiled modules? A: Python modules include the CPython runtime (~30-50MB). This is cached and shared across modules.
Q: Is it fast? A: Function calls have near-native overhead. The WASM boundary is much faster than HTTP/IPC. First load has a startup cost; subsequent calls are fast.
Q: What about async/await? A: Async functions are supported in the Python source. The JS bindings are synchronous for now.
License
MIT
Credits
Built on the incredible work of:
umo — Universal Modules for a polyglot world
