The economy.
60,000 plugins, each one arbitrary PHP with database root. The economy is why it won; the trust model is why it's the most attacked application surface on the internet. Every install is an act of faith, renewed on every update.
WordPress ate the web on two moats: a deployment story anyone could execute, and a plugin economy — and its permanent wound is that every plugin is a root shell. Directus and PocketBase modernized the derive-from-schema idea, but each kept only half. Realbook is the full set: PocketBase's deployment, Directus's data platform, WordPress's economy — behind a gate. One binary you scp. One Postgres. Plugins that can't name what they weren't granted.
The pattern keeps winning: give me a schema, I'll give you the product. WordPress ran it on posts and pages and took forty percent of the web. Directus and PocketBase ran it on real databases and took the developers who'd sworn off PHP. And every winner kept a fatal flaw — because the three things that matter have never fit in one runtime. Each kept one:
60,000 plugins, each one arbitrary PHP with database root. The economy is why it won; the trust model is why it's the most attacked application surface on the internet. Every install is an act of faith, renewed on every update.
Point it at Postgres, get the admin and the APIs — the right idea, on Node: a runtime, a node_modules tree, a compose file. Deployment is someone's job again, and the someone is you.
Brilliant, SQLite-shaped, scp-and-run — the WordPress install story finally modernized. But the extension story tops out at hooks compiled into your own build. There is no economy, and by design there can't be one.
The economy, the platform, and the binary — because nobody had a runtime that could load governed native plugins into one process. Interpreters can't gate what they can't see; compiled binaries can't load what they didn't ship.
Four verbs, one binary. Realbook is written in G# — David Obando's modern .NET language, real and public at v0.3 with a compiler, an MSBuild SDK, and VS Code tooling — and compiles to ordinary CLR assemblies, which means every BCL type and NuGet package is already inside the tent. The framework ships no scaffolds and generates no code you own. It derives, continuously.
Point it at an existing Postgres, or declare data classes in G# and let it create the tables. Either way: tables, relations, and enums become the catalog — the single model everything downstream is derived from. Legacy databases walk in as they are.
The admin UI, REST + realtime APIs over SignalR, auth, roles, row-level rules, and file handling — derived, not scaffolded. There is no generated code to drift. Change the schema and the product follows, the same way a view follows a table.
One self-contained binary: realbook serve.
scp it to a $4 VPS, write a systemd unit, done. No runtime to install, no
node_modules to ship, no compose file to explain. The deployment story is the
onboarding story.
Signature checked against the publisher's key. Capability manifest read aloud —
charges.write, not
contacts.read — and
granted explicitly. Then loaded hot into an isolated AssemblyLoadContext, without a
restart. Revoke unloads it just as cleanly.
The canonical exchange: a publisher ships an assembly, and the gate answers — before
anything runs — with a transcript. Everything on the left is plain G#, faithful to the
shipped language tour — @-style
attributes, Go-style parameters, if let
over a nullable result; everything on the right happens before the plugin's first
instruction executes.
package Stripe.Payments import Realbook.Plugin import Stripe @Plugin("stripe-payments", Capabilities: ["charges.write", "orders.read"]) class StripePayments { let charges Granted[Charges] // injected by the gate async func onOrderPaid(order Order) { if let charge = await charges.create(order.total) { order.receipt = charge.id ?? "" } } }
install stripe-payments v1.4.2 · publisher: acme-labs signature ✓ acme-labs key · pinned manifest charges.write ✓ orders.read ✓ contacts.* — not requested, not granted load ✓ isolated AssemblyLoadContext · no restart hooks ✓ onOrderPaid ⇠ orders.paid admin ✓ new card: Payments → live. revoke = unload — no orphaned tables, no zombie hooks.
The capability object is the only door. An ungranted API isn't rejected at runtime — it is absent from the plugin's world at load time; the code that would call it has nothing to call it on. And because plugins are CLR assemblies — and gsc really does emit ordinary managed assemblies, this is a fact about the shipped compiler, not a hope — the economy is polyglot from day one: C# shops publish, G# shops publish, F# shops publish if they like — the gate doesn't care what compiled you, only what you're asking to touch.
Signature and manifest are paperwork — necessary, static, and silent about behavior. So before a grant, realbook makes its own metaphor literal: the candidate plugin performs. The gate forks a snapshot of the data, loads the plugin into an isolated context with every outbound call captured, and replays yesterday's real event stream against it. What comes back is not a claim. It is a transcript of what the plugin actually did with your actual traffic — produced before its first instruction ever runs live.
$ realbook audition stripe-payments stage ✓ forked snapshot · isolated ALC · outbound captured replay ✓ yesterday's event stream · 41,882 events · 24h behavior charges.write 312 ✓ within manifest orders.read 1,102 ✓ within manifest contacts.* 0 · never attempted webhooks 3 fired · captured, not delivered verdict clean audition · transcript pinned to listing grant? the transcript is the argument.
Auditions re-run on every update, which turns the transcript history into a drift detector: a v1.5 that suddenly reads tables v1.4 never touched is a headline at the gate, not a diff buried in a changelog. And because the latest transcript is pinned to the marketplace listing, “what does this plugin actually do” is answered with evidence instead of a README — WordPress can't do this (arbitrary PHP, no event stream) and npm can't do this (no runtime gate); realbook can because the stream and the gate already exist.
Code Access Security died for a reason; AssemblyLoadContext isolates loading, not malice. The capability gate is discipline plus review plus signing — a strong deterrent and a clean contract, not a sandbox. Real sandboxing means out-of-process or WASM plugin hosts, and realbook holds that lane in reserve for hostile-plugin tiers, stated plainly rather than implied away.
An AOT-compiled binary cannot load assemblies at runtime. So realbook with plugins ships as self-contained CoreCLR — roughly 80 MB, still one file — and a lean AOT build exists only for plugin-free deploys. Two artifacts, one honest tradeoff, chosen in favor of the economy.
A plugin can play beautifully in replay and differently on stage — detect the sandbox, wait thirty days, trigger on an event yesterday's stream didn't contain. The audition raises the cost of malice and catches sloppiness nearly for free, but it is a screen, not a proof: re-audition on update, runtime capability accounting, and the out-of-process tier remain the deeper walls behind it.
WordPress's moat is twenty years of plugins solving twenty years of niches. Realbook starts at zero, and its gate — the whole point — is also a barrier to the sloppy long tail that made WordPress huge. The bet is that a smaller, vouched-for catalog beats a vast untrusted one; the bet is not yet won.
Real products outgrow generic admin. The escape hatch — eject a chart into owned G# code, chord's territory — must be genuinely first-class, or realbook becomes a prototype trap: wonderful for the first month, resented by the twelfth.
Models write C# fluently and G# barely. The language is further along than a sketch — a full written spec, a compiler, dozens of releases — but it is v0.3 from one primary maintainer, and no model has trained on it. Plugins can be C#, and the G# surface a plugin author touches is thin — but the loss is real and stated, not waved away with "the models will catch up."
A bad legacy schema derives a bad product: cryptic column names become cryptic admin labels, missing foreign keys become missing relations. Introspection is honest, not redemptive — realbook shows you your database as it is, and fixing it is still your job.
The pitch, in one sentence: point realbook at a Postgres and get the admin, the APIs, the auth, and the files as one binary you scp — then grow it through a plugin economy where every extension is signed, capability-scoped, and unable to name a single thing it wasn't granted.