Thirteen names are accepted by --target. Ten are server targets that
emit a complete HTTP + Action Cable application; the rest are
variations on those. This page says what each needs and how far each
is tested — which is the honest measure of how much to trust it.
| Target | Emits | Prerequisites to build and run |
|---|---|---|
rust |
Cargo crate (axum, rusqlite) | Rust 1.85+, SQLite library |
go |
Go module | Go 1.24+ |
typescript |
Node package | Node.js 24+ |
crystal |
shard | Crystal 1.10+, SQLite library |
elixir |
Mix project | Elixir 1.15+ |
kotlin |
Gradle build (JVM) | JDK 17+, Gradle 8+ |
swift |
Swift package | Swift 6+; on Linux libsqlite3-dev |
python |
Python project (uv) |
Python 3.11+, uv |
csharp |
.NET solution | .NET SDK 10+ |
ruby |
Ruby tree — the framework runtime in Ruby, no Rails | Ruby 3.4+, bundler, SQLite; Node for the asset build |
All ten serve on :3000, speak Action Cable at /cable, use SQLite at
storage/development.sqlite3, and are seeded by
sqlite3 storage/development.sqlite3 < db/seed.sql. Each ships the
app's model and controller tests and a Playwright e2e/ suite; the
sqlite3 CLI and Node.js 24+ are needed for the latter.
| Target | What it is |
|---|---|
jruby |
The ruby emit with prebuilt assets and JRuby run/test commands. JRuby 10+ (JDK 21+). |
spinel |
The ruby shape packaged as a spin project for ahead-of-time compilation to a native binary. Needs the Spinel compiler; spinel.md. |
typescript-worker |
The typescript emit bundled to run in a browser SharedWorker, with SQLite compiled to WebAssembly, for the in-browser demos. Node.js 24+ to bundle; no server. |
The lanes below run across targets in scheduled full validation, or when
requested with ci:full. Ordinary PRs use a Ruby floor plus targeted
additions for the files they change. After Full goes red, maintainers can
narrow fix rounds with focus labels (ci:swift, ci:extras, …) — see
CI coverage. Pushes to canonical main run that Ruby
floor plus the full Spinel suite; extra-language SDKs wait for the
four-hour schedule. Maintainers can request full PR coverage with ci:full. The lanes use the blog fixture
(fixtures/real-blog: articles, comments,
nested routes, validations, Turbo Streams over Action Cable, Tailwind)
unless another app is named. A target's row in
RELEASES.md records where these stood at the
snapshot.
| Lane | What it proves | Targets |
|---|---|---|
| compare | The emitted server renders the same DOM as live Rails, node for node, on every page of the fixture; JSON endpoints value for value. verifying.md. |
rust, go, typescript, crystal, elixir, kotlin, swift, python, csharp, ruby, jruby, spinel |
| smoke | The emitted README's own commands — build, setup, test, e2e in a real browser — run verbatim from the published archive. | rust, go, typescript, crystal, elixir, kotlin, swift, python, csharp, ruby, jruby, spinel |
| framework tests | The framework runtime's own test suite (runtime/ruby/test/) passes when transpiled to the target — the runtime is itself transpiled, so this is the target's Active Record, Action Controller and Action View under test. |
crystal, kotlin, swift, typescript, ruby, spinel; rust on a subset |
| toolchain | Unit tests emitted for a smaller fixture (tiny-blog) compile and pass — the absent-feature shape the full blog can't exercise. |
crystal, elixir, python, typescript, csharp, spinel (go, rust, kotlin, swift are covered by smoke instead and keep their harness for the dev loop) |
| Campfire | Basecamp's Campfire — attachments, rich text, web push, bots, search, boosts, multiple rooms and users — compared against live Rails page by page, its own test suite run against the transpile, and its Action Cable broadcasts checked frame for frame. | ruby, spinel |
The last row is the important asymmetry. The nine compiled and JVM
targets are proven on the blog; the Ruby shape — on CRuby, and
compiled by Spinel — is proven on Campfire, a real product with a real
surface, and is the lane the framework runtime is developed against
first. When a Rails feature lands in roundhouse it lands there, and
reaches the other targets as their emitters and runtimes catch up.
rails-coverage.md is the feature-level view of
that gap.
The conformance bar is a passing compare result against the fixture,
not the assumption that every target was checked on an ordinary PR.
A page that renders one node differently — an
attribute missing, a whitespace text node — is red. That is
deliberately a higher bar than "the tests pass": it means the emitted
app is the same app, as a browser or a scraper would see it, not a
reimplementation that happens to agree on the tested paths.
The cost of the bar is that a target can drop off it. A target whose
compare lane goes red on main and stays red is not on the list for
the next snapshot, and its row in RELEASES.md says so.