Rapid development platform built by AI
The brief: take the fastest way to build a web application and bring it completely up to date. The answer is an opinionated platform pairing CFML, which humans can easily understand with Rust, which agents verify and machines run at lightning speed with minimal footprint.
Everything a modern application needs is already included. Less to install and for an agent to get wrong.
Every layer above is already inside the binary you download. Extend capabilities with native Rust or .rcx extensions
5 ways to deploy including Cloudflare edge
The WASM target has its own limits: databases go through Hyperdrive, and some of the standard library is unavailable.
A second CFML runtime, written by AI
Lucee is the open-source CFML engine most people run, and it is the reference here:
every test has to pass on Lucee first. BoxLang went the other way, onto the JVM. This
is the CFML you already write with no virtual machine under it, in one binary that
starts instantly and holds around 60 MB under load. Where it runs short you write
the missing piece in Rust: an .rcx file dropped in a
directory arrives as an ordinary function, or compiles into the binary itself.
Almost all of it was written by AI, which works better than it sounds. Rust will not compile the kind of code a generator gets wrong, and CFML is small enough to have one obvious way to do most things. Between them an agent gets to a right answer and stays there. You are reading a page it served.
A component is an MCP server
One CFC under /mcp/ is a server that Claude Code, or any
other agent runtime, can discover and call. It is served from the same process and
port as your pages, or launched over stdio as a subprocess. No sidecar, no SDK, no
second runtime to keep alive.
Annotate a method with tool= and the JSON Schema is read
off the CFML signature: types, defaults, which arguments are genuinely required, and
descriptions from the doc comment. Results are shaped on the way out too, so a query
arrives as an array of row objects rather than the
{COLUMNS, DATA} envelope no MCP client understands.
Resources, prompts, progress and logging over SSE are all there, and
secured gates a tool on the same contract that gates a
WebSocket handler. A tool can also call back:
mcp().sample() borrows the client's own model, so no API
key of yours is involved. In the other direction,
mcpConnect() makes anyone else's MCP server callable from
a page.
// One CFC under /mcp/ is one server. There is no other configuration.
component mcp="crm" description="Deal lookups for agents" {
/** @region.description Sales region to report on */
function topDeals( required string region, numeric limit = 10 )
tool = "top_deals"
description = "Highest value open deals in a region"
readOnly = true
{
return queryExecute(
"select name, value from deals where region = :region limit :limit"
, { region = arguments.region, limit = arguments.limit }
);
}
}
$ rustcfml --serve ./webroot # http://localhost:8500/mcp/crm
$ rustcfml mcp crm ./webroot # …or over stdio, as a subprocess
Realtime on the same port as your pages
No Node sidecar, no separate container, no broker to run. A component with a
socket attribute is a channel, and the lifecycle
methods are the whole API: rooms, presence, auth at the handshake,
lastEventId resumability and multi-node fan-out.
A return value from onMessage becomes the client's
ack.
Both transports are served: raw WebSocket and socket.io, so an existing
socket.io client connects without changes. Underneath it, cfthread
runs on real OS threads rather than a green-thread pool.
// The whole channel. There is no other configuration.
component socket="/chat" encoding="json" {
function onConnect( socket ) {
socket.join( "lobby" );
socket.emit( "welcome", { id = socket.id() } );
}
function onMessage( socket, message ) {
io().to( "lobby" ).emit( "message", {
from = socket.id()
, text = message.text
} );
return { delivered = true }; // the client's ack
}
}
The Java you forgot you depended on
Applications reach into Java more than their authors remember: a
StringBuilder in a loop, a
ConcurrentHashMap behind a cache. There is no JVM here
to answer them, so over a hundred classes are shimmed instead. There are enough
of them that CFWheels configures itself from an adapter it ships
upstream, and
Preside runs with no application changes.
// The Java already in your codebase, unchanged.
sb = createObject( "java", "java.lang.StringBuilder" ).init();
for ( row in leads ) {
sb.append( row.region ).append( ", " );
}
id = createObject( "java", "java.util.UUID" )
.randomUUID().toString();
// A real pool, from the library you already know.
pool = createObject( "java"
, "java.util.concurrent.Executors" )
.newFixedThreadPool( 4 );
Drop to Rust for the hot path. Keep writing CFML.
Every high-level language needs an escape hatch, and the quality of that hatch
decides how far the language gets. Declare your functions in one macro, build, and
drop an .rcx file in a directory: a stock binary loads
it at start-up and they arrive as ordinary built-ins.
// One macro is the whole declaration.
module! {
name: "match",
version: "0.1.0",
bifs: { "hammingDistance" => hamming },
}
fn hamming<'a>( ctx: &'a Ctx, args: &[ Value<'a> ] )
-> Result<Value<'a>> { /* … */ }
$ rustcfml ext build .
✓ match-0.1.0-macos-aarch64.rcx
// match.cfm: now it is just a function.
score = hammingDistance( left, right )
You can see inside it in production
Four layers of tooling, every one of them off until you ask, and costing nothing at all while it is off.
The classic debug footer is still there: queries, template times, exceptions and scopes, gated four ways so it never leaks to the public. Above it sits a threshold-gated sampling profiler in the FusionReactor mould, which only starts snapshotting a request's CFML call stack once that request has already run too long. A request that stays under the threshold costs one relaxed atomic load per line.
Above that, OpenTelemetry traces over OTLP and Prometheus RED metrics, so a slow request in production lands in Tempo, Jaeger, Honeycomb or Datadog like anything else on your estate. Export runs on a background batch thread and never sits on the request path.
The footer and the profiler are in every build. Traces, metrics and the
--profile flamegraph come from a build with the
obs-otel and obs-pprof
features, and neither is available in the WebAssembly target.
# RED metrics, scraped straight off the engine.
$ curl -s localhost:8500/__rustcfml/metrics | head -3
rustcfml_http_requests_total{route="/api/deals"} 12841
rustcfml_http_request_duration_seconds_bucket{le="0.05"} 12604
rustcfml_db_query_duration_seconds_sum 41.907
Run a page in the next two minutes
No trial, no account, no administrator to log into. Point one flag at a directory of templates and it serves them.