git.iko.soy/opencode-android
on master help sign in
git clone ssh://git.iko.soy/opencode-android

opencode-android

A native Android client for the opencode server (the sst/opencode AI coding agent), built with Crux (a Rust core), Kotlin, and Jetpack Compose.

Connect to a running opencode serve, browse and create sessions, and chat with the agent — assistant replies (text, reasoning, and tool calls) stream in live over the server's SSE event stream.

Connect → Sessions → Chat, with token-by-token streaming.

Architecture

The app follows the Crux pattern: all application logic lives in a pure, platform-agnostic core; the platform is a thin shell that renders the core's view model, sends it events, and performs the side effects it requests.

┌─────────────────────────── shared/ (Rust) ───────────────────────────┐
│  Crux core — the single source of truth                               │
│    • Model / Event / Effect / ViewModel                               │
│    • update(): connect+auth, sessions, chat, SSE stream application    │
│    • crux_http for HTTP effects; unit-tested with `cargo test`         │
└───────────────────────────────────────────────────────────────────────┘
                         ▲ mirrored, behaviour-for-behaviour
┌─────────────────────────── app/ (Kotlin) ────────────────────────────┐
│  Jetpack Compose shell                                                 │
│    • OpencodeCore  — Kotlin port of the reducer (same ViewModel)       │
│    • HttpClient (OkHttp) + SseClient (okhttp-sse)  — the effects       │
│    • Compose UI: Connect / Sessions / Chat                             │
└───────────────────────────────────────────────────────────────────────┘

Why a Kotlin port instead of a JNI .so?

Crux normally compiles the Rust core to a native library and the shell talks to it over an FFI bridge. That requires an Android cross-compilation toolchain (NDK + a Rust std for the *-linux-android targets). This project's dev environment intentionally ships without an NDK, so instead:

The FFI boundary is kept clean, so the day an NDK is available the Kotlin port can be swapped for the compiled .so behind the same seam. The crate already builds as a cdylib/staticlib and a codegen binary is wired for Crux type-generation.

Project layout

flake.nix                     Reproducible dev shell (JDK 17, Gradle, Rust, Android SDK 35)
shared/                       Crux core (Rust)
  src/app.rs                  App: Model, Event, Effect, ViewModel, update, view, tests
  src/protocol.rs             Lenient serde wire types for the opencode HTTP + SSE API
  src/bin/codegen.rs          Type-generation entry point (feature = "typegen")
generated/                    Crux-generated FFI-shared JVM types (from `codegen`)
app/                          Android app (Kotlin + Compose)
  src/main/java/soy/iko/opencode/
    core/                     OpencodeCore (reducer port), Protocol, HttpClient, SseClient
    ui/                       Compose screens (Connect/Sessions/Chat), theme, components
    MainActivity.kt, CoreViewModel.kt

Getting started

Dev shell

Everything you need is provided by the Nix flake:

nix develop          # or: direnv allow  (an .envrc with `use flake` is included)

This puts JDK 17, Gradle, rustc/cargo, and the Android SDK (platform 35, build-tools 35.0.0) on your PATH.

Build & test

# Rust core — logic + streaming unit tests
cd shared && cargo test

# Android app — debug APK
./gradlew assembleDebug          # -> app/build/outputs/apk/debug/app-debug.apk

# Android unit tests + lint
./gradlew testDebugUnitTest lintDebug

Run against a server

Start opencode's server on your machine or LAN:

opencode serve --port 4096       # optionally behind OPENCODE_SERVER_PASSWORD

Install the APK, launch the app, and enter the server URL (e.g. http://192.168.1.10:4096). If the server was started with a password the app detects the 401, shows credential fields, and connects with HTTP Basic auth.

Cleartext HTTP is enabled so you can reach a http:// server on your LAN.

The opencode API this client speaks

Continuous integration & releases

Notes & limitations

License

Apache-2.0.