intertwingly

It’s just data

Untyped, on Purpose

Image

Most type systems force a single bet about where to set the dial between programmer annotations and compiler inference. Today Roundhouse declined to set it. Ty::Untyped landed as a first-class type — the IR's load-bearing primitive for deferring per-target, per-code-category, per-stage strictness decisions until there's evidence about what to decide.

Round Trip

Image

Yesterday I closed with the bet that "within a few iterations the round trip works end to end." Iteration one closed faster than that rhetoric implied. The demo is two make commands and a working blog on localhost:3000 — Rails source on the way in, transpiled Spinel-subset Ruby on the way out, real-time Turbo broadcasts and SQLite persistence in between.

Two Compilers, One Subset

Image

An update on Two Compilers, One Moment. Two days ago I described overlapping inputs and non-overlapping value. The work since suggests the overlap is sharper than that — the IR roundhouse needs internally is, structurally, the Spinel subset. Discovered, not designed.

Two Compilers, One Moment

Image

Two compilers, started a month apart. The first by Ruby's creator. The second by someone with no knowledge of the first. The interesting question isn't which one is right — it's what changed in the surrounding landscape that made now the moment.

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.