intertwingly

It’s just data

Static Types for Dynamic Targets

Image

Ruby's + means addition between integers, concatenation between strings, concatenation between arrays, and a runtime raise between an integer and a string. To produce correct output for one operator in six target languages, a compiler has to know the operand types at each site — in Rust where types are mandatory, and equally in Elixir, Python, and TypeScript where they're not. Roundhouse's bet rides on that observation. Today two pieces of load-bearing infrastructure landed: RBS ingestion on both sides of the compiler, and a diagnostic pipeline that surfaces what the typed IR can't resolve.

Rails Was Already Typed

Image

Rails apps come pre-typed. Schema declares column types, conventions thread them across associations and controllers, and standard inference fills in the rest. None of it requires annotations — the information is already in the source. Roundhouse reads it, types every expression, and emits to seven targets. As of today, the TypeScript and Rust targets produce the same DOM as Rails on the standard blog scaffold.

Introducing Roundhouse

Image

Roundhouse reads Rails applications and produces standalone projects in other target languages — the deployment target becomes a compiler flag rather than a runtime choice. It started two days ago. Here's what it is, what it can do today, and why the Rails subset it targets is larger than it sounds.

Nine Days

Image

The internet says Claude Code is nerfed. That has not been my experience. A Rails blog app, transpiled to six compiled languages with real-time WebSocket broadcasting, downloadable binaries, 126+ tests. Nine days.

Rust on Rails

Image

Railcar can now transpile a Rails application to Rust. The same blog app generates a working Axum server with rusqlite, Turbo Streams — 21 tests passing, zero compiler warnings, the sixth target language.

Go on Rails

Image

Railcar can now transpile a Rails application to Go. The same blog app generates a working net/http server with view functions, modernc.org/sqlite, and Turbo Streams — 21 tests passing, the fifth target language.

Elixir on Rails

Image

Railcar can now transpile a Rails application to Elixir. The same blog app generates a working Plug + Bandit server with EEx templates, Exqlite, and Turbo Streams — 21 tests passing, the first functional language target.

TypeScript on Rails

Image

Railcar can now transpile a Rails application to TypeScript. The same blog app generates a working Express server with EJS templates, better-sqlite3, Turbo Streams — 21 tests passing, the third target in a single day.

Python on Rails

Image

Railcar can now transpile a Rails application to Python. The same blog app that compiles to Crystal also generates a working Python web application with aiohttp, SQLite, Tailwind CSS, and Turbo Streams — 21 tests passing, full CRUD with nested resources.

Crystal on Rails

Image

Compiling arbitrary Ruby is hard. Generating type signatures for arbitrary Ruby is hard. But Rails isn't arbitrary Ruby — it's a DSL with known semantics. Railcar exploits that to do three things: transpile Rails apps to Crystal, provide a Rails-compatible Crystal framework, and generate RBS type signatures.

Rails on the BEAM

Image

Same blog. Same Turbo Streams. But now a runtime crash doesn't crash the server, broadcasts span nodes without Redis, and you have a path to Phoenix.

Calling JavaScript from Ruby

Image

Ruby can call C. Ruby can call Python. But calling JavaScript has always meant eval strings or manual bundling. Boax embeds the Boa JS engine in Ruby via Rust, letting you call JS libraries with the same proxy-object pattern Ruby developers already know.

The Transpiler That Reads Your Whole App

Image

Most transpilers work file by file. But Rails encodes meaning across files — controller names imply view paths, associations imply async behavior, group_by in a controller implies Map operations in a view. Juntos reads the whole application and carries that knowledge forward.

Writebook on Juntos

Image

We took Basecamp's Writebook — a real Rails 8 application — and ran it through Juntos. The server starts, the database initializes, and HTTP requests are served. Here's what we learned.

Ruby2JS: Self-Hosted

Image

The Ruby2JS documentation site now compiles itself. Every live demo runs Ruby2JS transpiled by Ruby2JS — no Opal, no server, just the transpiler in your browser.

Same Code, Same Output

Image

A Rails blog transpiled to JavaScript produces identical HTML. Not similar. Not close enough. Identical. Here's how I proved it and what I found along the way.

Three Tiers, Zero Servers

Image

A Rails blog running across three browser Workers — SharedWorker for application logic, dedicated Worker for SQLite with OPFS persistence, main thread for Turbo and Stimulus. Under 600KB gzipped. No server required.

Full Stack Watch Mode

Image

The full test suite—model tests, controller tests, system tests—running continuously on every save at 47ms per test. Faster than jsdom. In a real browser. The tests DHH gave up on, running on every save.

Capybara Without the Browser Tax

Image

Transpiling Ruby to JavaScript is usually discussed in terms of deployment targets. But it has a second payoff: system tests that run in 75ms with zero flakiness. Same Capybara DSL. No browser required.

Routing to Identity

Image

Kubernetes routes to capacity. Cell orchestration routes to identity. These are fundamentally different problems, and everything downstream follows from which one you're solving.