
Server-driven UI runtime rendering Compose widgets from networked JavaScript bundles, enabling instant UI updates without app-store releases; includes visual editor with live canvas, code export, signed bundles.
Server-driven UI for Compose Multiplatform. Render Kotlin Compose UI on Android and iOS from JavaScript bundles delivered over the network — ship UI updates without an app-store release.
▶ Try it in your browser, zero install: the Keliver Portal playground — the visual editor with a live canvas, 60+ widgets, data bindings with mock previews, and one-click Export Kotlin (the output is real code).
Status: public on Maven Central —
0.4.1. AddmavenCentral()and depend ondev.keliver:keliver-host:0.4.1(host) /dev.keliver:keliver-guest:0.4.1(guest) — no GitHub PAT, no extra repo.keliver-materialis a Compose/Material3-parity widget library (76 widgets — seedocs/WIDGET_PARITY.md) so you build server-driven screens without authoring a schema.0.3.0adds Icon + ListItem, DropdownMenu/SegmentedButtonRow in the portal, and publishesdev.keliver:portal-sql(the SDUI data layer). Start a new app in seconds with keliver-init (below). Pre-1.0, API may still evolve; the wire format is stable within a line.
Keliver is a Cash App Redwood fork.
Upstream Redwood is great but is no longer being actively developed by
Cash App. Keliver picks up the foundation — redwood-runtime,
redwood-compose, redwood-treehouse, redwood-treehouse-host,
redwood-treehouse-host-composeui — and ships it under the dev.keliver
namespace with:
Already running on upstream Redwood? See
docs/MIGRATION_FROM_REDWOOD.md— the migration is mostly a scripted rename.
docs/KNOWN_BUGS.md
for the full list and each entry's status (fixed, worked around, or open).sample/, the reference/inventory app CI builds from the
published tools, and a brownfield product proof inside two existing apps in
2026-10) and get fixed; the changelog and docs/KNOWN_BUGS.md are honest
about what's still broken. There is no external adopter yet.You write Kotlin Compose UI in a separate guest module. That code
compiles to JavaScript via Kotlin/JS and gets bundled into a
.zipline file. Your host app downloads the bundle at runtime,
executes it in Zipline (a
QuickJS wrapper), and Keliver's protocol translates the guest's
widget tree into real Compose widgets on the host platform —
Android (Jetpack Compose), iOS (Compose Multiplatform), or anywhere
CMP runs.
The result: change a screen, push a new bundle, every user has it in seconds without an app-store cycle.
A typical guest screen looks like normal Compose:
class QuotesScreen : Screen {
@Composable override fun Content(navigator: Navigator) {
val provider = HostQuotesProviderBridge.instance
var quotes by remember { mutableStateOf<List<Quote>?>(null) }
LaunchedEffect(provider) {
quotes = provider?.getQuotes(filter = null) ?: emptyList()
}
Column(modifier = Modifier.fillMaxSize().padding(16, 16, 16, 16)) {
Text("Select Quote", style = SchemaTextStyle.TitleLarge)
LazyColumn {
quotes.orEmpty().forEach { q ->
LazyItem { QuoteCard(q) }
}
}
}
}
}The host wires services that the guest can call via Zipline RPC:
class QuotesAppSpec : TreehouseApp.Spec<SduiAppService>() {
override val name = "quotes"
override val manifestUrl = quotesManifestUrlFlow.asStateFlow()
override val serializersModule = SduiSerializersModule
private lateinit var quotesProvider: RealHostQuotesProvider
private lateinit var quoteNavigator: RealHostQuoteNavigator
override suspend fun bindServices(treehouseApp, zipline) {
// bindWithTimeout turns the silent bind-hang failure shape into
// an actionable timeout — see KNOWN_BUGS.md U1.
bindWithTimeout {
zipline.bind<HostConsole>("console", retain(AppHostConsole()))
}
requireSerializerOf<Quote>() // bind-time pre-flight — KNOWN_BUGS U3.
quotesProvider = RealHostQuotesProvider(
source = quotesSource,
scope = appScope,
ziplineDispatcher = treehouseApp.dispatchers.zipline,
)
bindWithTimeout {
zipline.bind<HostQuotesProvider>("quotes", quotesProvider)
}
quoteNavigator = RealHostQuoteNavigator(
scope = appScope,
uiDispatcher = treehouseApp.dispatchers.ui, // KNOWN_BUGS U8.
callback = onQuoteSelected,
)
zipline.bind<HostQuoteNavigator>("quote-nav", quoteNavigator)
}
override fun create(zipline: Zipline) = zipline.take<SduiAppService>("app")
}Beyond the library, this repo ships the Keliver Portal: a visual editor,
any code editor, and AI agents all edit the same screen document, with the
.kt file in git as the source of truth.
EDIT (any of) SHIP
Portal UI ─┐ Publish → compile the canonical
IDE / vim ─┼─► one UiDocument ──► Kotlin → Ed25519-sign → versioned,
AI (MCP) ─┘ (.kt in git = truth) capability-gated bundle → devices
│ verify the signature
┌────────────┼───────────────┐
web preview dev devices surgical .kt write-back
(mock rows, (live overlay, (comments survive edits)
fidelity) ~1s mirror)
screens/*.kt; edits
in your IDE appear live in the browser and on devices — no restart.scripts/keliver-dev.sh.See docs/PORTAL_USAGE.md (workflow) and
docs/PORTAL_V2_COMPLETE.md (architecture).
The playground is this editor running
serverlessly in wasm.
Good fit:
Less good fit:
A typical app uses Keliver for a slice of its surface area, not the
whole app: the 2026-10 product proof replaced one web feature (13 screens)
inside two existing apps (docs/ADOPTION_RETRO_2026-10.md).
New project in 60 seconds — grab keliver-portal-tools from the
latest release, then:
export PATH="$PWD/keliver-portal-tools/bin:$PATH"
keliver-init Acme && cd acme
./gradlew compileKotlinJs # your screens, type-checked against the keliver version the tools scaffold (0.4.1 until a tools release moves it)
keliver-portal . # visual editor + live preview → http://localhost:8096keliver-init scaffolds a standalone project whose screens are real Kotlin
Compose against the published dev.keliver:* artifacts — no keliver checkout.
Or just poke the hosted playground: http://keliver.me/keliver/.
Constraint, Yoga child-layout, universal-modifier, and widget-specific
sizing rules.The sample/ directory is a complete, runnable starter — a
Workouts screen (an API call + a host database + live search) built in both
architecture styles, with a green unit test. Copy it and rename, or run it
first to see the loop.
The repository is public and the libraries are on Maven Central; a docs site is not built yet, so these guides are the documentation.
docs/KNOWN_BUGS.md is the punch list (U1–U38),
each entry headed with its status. Open as of 2026-10-27: U19 (a live-preview
re-render), U20 (the editor's frame rate, measured but not assessed), U28 (a
false codeLoadFailed log line on every production-host start) and U38 (the
browser can keep a cached editor after switching to an app's own one).
U8 part 1 (@MainThread codegen) still has no Keliver-side fix: its root
cause is in Zipline's compiler plugin, tracked at
cashapp/zipline#1825, and the
workaround is documented.
Keliver is pre-1.0 — pin an exact dev.keliver:* version and expect
breaking API changes across 0.x. The public surface of every published module
is tracked by the binary-compatibility-validator on each build, so no API change
ships by accident. See docs/API_STABILITY.md.
docs/ROADMAP.md — the backlog, in priority order, with
a status line on each item. Where things stand: docs/CURRENT_STATE.md
(status at a glance) and docs/DELIVERY_PLAN.md
(the step-by-step Status table and next action).
PUBLIC_LAUNCH_ROADMAP.md records the one-time
work that took this repo public (complete).
Apache 2.0 — same as upstream Cash App Redwood. See LICENSE.txt.
Keliver is built on Cash App Redwood and Zipline. The original Redwood team did the hard architectural work; this fork picks up maintenance and adds the production-hardening that surfaces in real-world integrations.
Server-driven UI for Compose Multiplatform. Render Kotlin Compose UI on Android and iOS from JavaScript bundles delivered over the network — ship UI updates without an app-store release.
▶ Try it in your browser, zero install: the Keliver Portal playground — the visual editor with a live canvas, 60+ widgets, data bindings with mock previews, and one-click Export Kotlin (the output is real code).
Status: public on Maven Central —
0.4.1. AddmavenCentral()and depend ondev.keliver:keliver-host:0.4.1(host) /dev.keliver:keliver-guest:0.4.1(guest) — no GitHub PAT, no extra repo.keliver-materialis a Compose/Material3-parity widget library (76 widgets — seedocs/WIDGET_PARITY.md) so you build server-driven screens without authoring a schema.0.3.0adds Icon + ListItem, DropdownMenu/SegmentedButtonRow in the portal, and publishesdev.keliver:portal-sql(the SDUI data layer). Start a new app in seconds with keliver-init (below). Pre-1.0, API may still evolve; the wire format is stable within a line.
Keliver is a Cash App Redwood fork.
Upstream Redwood is great but is no longer being actively developed by
Cash App. Keliver picks up the foundation — redwood-runtime,
redwood-compose, redwood-treehouse, redwood-treehouse-host,
redwood-treehouse-host-composeui — and ships it under the dev.keliver
namespace with:
Already running on upstream Redwood? See
docs/MIGRATION_FROM_REDWOOD.md— the migration is mostly a scripted rename.
docs/KNOWN_BUGS.md
for the full list and each entry's status (fixed, worked around, or open).sample/, the reference/inventory app CI builds from the
published tools, and a brownfield product proof inside two existing apps in
2026-10) and get fixed; the changelog and docs/KNOWN_BUGS.md are honest
about what's still broken. There is no external adopter yet.You write Kotlin Compose UI in a separate guest module. That code
compiles to JavaScript via Kotlin/JS and gets bundled into a
.zipline file. Your host app downloads the bundle at runtime,
executes it in Zipline (a
QuickJS wrapper), and Keliver's protocol translates the guest's
widget tree into real Compose widgets on the host platform —
Android (Jetpack Compose), iOS (Compose Multiplatform), or anywhere
CMP runs.
The result: change a screen, push a new bundle, every user has it in seconds without an app-store cycle.
A typical guest screen looks like normal Compose:
class QuotesScreen : Screen {
@Composable override fun Content(navigator: Navigator) {
val provider = HostQuotesProviderBridge.instance
var quotes by remember { mutableStateOf<List<Quote>?>(null) }
LaunchedEffect(provider) {
quotes = provider?.getQuotes(filter = null) ?: emptyList()
}
Column(modifier = Modifier.fillMaxSize().padding(16, 16, 16, 16)) {
Text("Select Quote", style = SchemaTextStyle.TitleLarge)
LazyColumn {
quotes.orEmpty().forEach { q ->
LazyItem { QuoteCard(q) }
}
}
}
}
}The host wires services that the guest can call via Zipline RPC:
class QuotesAppSpec : TreehouseApp.Spec<SduiAppService>() {
override val name = "quotes"
override val manifestUrl = quotesManifestUrlFlow.asStateFlow()
override val serializersModule = SduiSerializersModule
private lateinit var quotesProvider: RealHostQuotesProvider
private lateinit var quoteNavigator: RealHostQuoteNavigator
override suspend fun bindServices(treehouseApp, zipline) {
// bindWithTimeout turns the silent bind-hang failure shape into
// an actionable timeout — see KNOWN_BUGS.md U1.
bindWithTimeout {
zipline.bind<HostConsole>("console", retain(AppHostConsole()))
}
requireSerializerOf<Quote>() // bind-time pre-flight — KNOWN_BUGS U3.
quotesProvider = RealHostQuotesProvider(
source = quotesSource,
scope = appScope,
ziplineDispatcher = treehouseApp.dispatchers.zipline,
)
bindWithTimeout {
zipline.bind<HostQuotesProvider>("quotes", quotesProvider)
}
quoteNavigator = RealHostQuoteNavigator(
scope = appScope,
uiDispatcher = treehouseApp.dispatchers.ui, // KNOWN_BUGS U8.
callback = onQuoteSelected,
)
zipline.bind<HostQuoteNavigator>("quote-nav", quoteNavigator)
}
override fun create(zipline: Zipline) = zipline.take<SduiAppService>("app")
}Beyond the library, this repo ships the Keliver Portal: a visual editor,
any code editor, and AI agents all edit the same screen document, with the
.kt file in git as the source of truth.
EDIT (any of) SHIP
Portal UI ─┐ Publish → compile the canonical
IDE / vim ─┼─► one UiDocument ──► Kotlin → Ed25519-sign → versioned,
AI (MCP) ─┘ (.kt in git = truth) capability-gated bundle → devices
│ verify the signature
┌────────────┼───────────────┐
web preview dev devices surgical .kt write-back
(mock rows, (live overlay, (comments survive edits)
fidelity) ~1s mirror)
screens/*.kt; edits
in your IDE appear live in the browser and on devices — no restart.scripts/keliver-dev.sh.See docs/PORTAL_USAGE.md (workflow) and
docs/PORTAL_V2_COMPLETE.md (architecture).
The playground is this editor running
serverlessly in wasm.
Good fit:
Less good fit:
A typical app uses Keliver for a slice of its surface area, not the
whole app: the 2026-10 product proof replaced one web feature (13 screens)
inside two existing apps (docs/ADOPTION_RETRO_2026-10.md).
New project in 60 seconds — grab keliver-portal-tools from the
latest release, then:
export PATH="$PWD/keliver-portal-tools/bin:$PATH"
keliver-init Acme && cd acme
./gradlew compileKotlinJs # your screens, type-checked against the keliver version the tools scaffold (0.4.1 until a tools release moves it)
keliver-portal . # visual editor + live preview → http://localhost:8096keliver-init scaffolds a standalone project whose screens are real Kotlin
Compose against the published dev.keliver:* artifacts — no keliver checkout.
Or just poke the hosted playground: http://keliver.me/keliver/.
Constraint, Yoga child-layout, universal-modifier, and widget-specific
sizing rules.The sample/ directory is a complete, runnable starter — a
Workouts screen (an API call + a host database + live search) built in both
architecture styles, with a green unit test. Copy it and rename, or run it
first to see the loop.
The repository is public and the libraries are on Maven Central; a docs site is not built yet, so these guides are the documentation.
docs/KNOWN_BUGS.md is the punch list (U1–U38),
each entry headed with its status. Open as of 2026-10-27: U19 (a live-preview
re-render), U20 (the editor's frame rate, measured but not assessed), U28 (a
false codeLoadFailed log line on every production-host start) and U38 (the
browser can keep a cached editor after switching to an app's own one).
U8 part 1 (@MainThread codegen) still has no Keliver-side fix: its root
cause is in Zipline's compiler plugin, tracked at
cashapp/zipline#1825, and the
workaround is documented.
Keliver is pre-1.0 — pin an exact dev.keliver:* version and expect
breaking API changes across 0.x. The public surface of every published module
is tracked by the binary-compatibility-validator on each build, so no API change
ships by accident. See docs/API_STABILITY.md.
docs/ROADMAP.md — the backlog, in priority order, with
a status line on each item. Where things stand: docs/CURRENT_STATE.md
(status at a glance) and docs/DELIVERY_PLAN.md
(the step-by-step Status table and next action).
PUBLIC_LAUNCH_ROADMAP.md records the one-time
work that took this repo public (complete).
Apache 2.0 — same as upstream Cash App Redwood. See LICENSE.txt.
Keliver is built on Cash App Redwood and Zipline. The original Redwood team did the hard architectural work; this fork picks up maintenance and adds the production-hardening that surfaces in real-world integrations.