K2 is an Android mobile client for the OpenClaw AI gateway. Built with .NET MAUI, it delivers a WhatsApp-style conversational interface with voice input, real-time text-to-speech, and a persistent background connection to a self-hosted AI agent.
- Real-time AI chat — Streams responses from an OpenClaw gateway agent over WebSocket
- Voice mode — Continuous speech-to-text via Android
SpeechRecognizerwith live RMS energy visualization - Text-to-speech — Configurable TTS speed for agent audio playback (24 kHz)
- Animated orb — SkiaSharp-rendered orb that reacts to listening, processing, and speaking states
- Background service — Android foreground service keeps the WebSocket alive and posts notifications when messages arrive while the app is backgrounded
- Multi-host failover — Automatically tries each configured gateway host on connection failure
- Device identity — Ed25519 keypair generated on first run; device ID derived from the public key hash for authenticated gateway sessions
- Persistent settings — All configuration saved to
k2_settings.jsonin app data; user profile stored in MAUIPreferences - Multiple chat sessions — Navigate between named agent sessions
- Shell command execution — Agent can suggest Linux shell commands; user approves before execution (configurable allow-list)
| Requirement | Version |
|---|---|
| .NET | 9.0 |
| .NET MAUI | 9.0 |
| Android SDK | API 24+ (Android 7.0) |
| Visual Studio | 2022 17.8+ or 2026 |
| Package | Purpose |
|---|---|
Microsoft.Maui.Controls |
UI framework |
SkiaSharp.Views.Maui.Controls |
Orb canvas rendering |
Portable.BouncyCastle |
Ed25519 device keypair signing |
git clone https://github.com/V4LKYR13101/K2.Maui.git
cd K2.MauiOpen K2.Maui.csproj or the solution file in Visual Studio and allow NuGet packages to restore.
Edit Config.cs and update the default gateway hosts and auth token, or configure them at runtime via the in-app Connection Settings page:
public static string GatewayUri { get; set; } = "ws://your_host:18789";
public static string AuthToken { get; set; } = "your_token";
public static string AgentId { get; set; } = "wabot";Select an Android device or emulator and press F5 (or Run).
Note: Voice mode requires a physical device with a working microphone. The Android emulator does not support
SpeechRecognizerreliably.
K2.Maui/
├── App.cs # Application entry point
├── AppShell.cs # Shell navigation definition
├── Config.cs # All runtime configuration & persistence
├── K2Service.cs # Core business logic (connect, send, TTS, shell)
├── GatewayClient.cs # WebSocket client for the OpenClaw protocol
├── DeviceIdentity.cs # Ed25519 device keypair & token management
├── AudioCapture.cs # Android SpeechRecognizer wrapper
├── OrbRenderer.cs # SkiaSharp animated orb state & rendering
├── Theme.cs # App-wide color & style constants
├── Icons.cs # Icon font glyph constants
│
├── Pages/
│ ├── ChatPage.cs # Main WhatsApp-style chat UI
│ ├── ChatListPage.cs # Session list / home screen
│ ├── NameSetupPage.cs # First-run display name setup
│ ├── SplashPage.cs # Splash / loading screen
│ ├── SettingsPage.cs # Settings hub
│ ├── ConnectionPage.cs # Gateway host & auth token settings
│ ├── AudioSettingsPage.cs # TTS speed & voice mode settings
│ ├── ChatSettingsPage.cs # Font size & display settings
│ ├── AccountSettingsPage.cs # User profile / display name
│ └── ProfilePage.cs # Agent profile view
│
└── Platforms/Android/
├── MainActivity.cs # Android activity host
├── MainApplication.cs # Android application class
├── K2BackgroundService.cs # Foreground service for background connectivity
└── K2WidgetProvider.cs # Home screen widget provider
All settings are persisted to <AppDataDirectory>/k2_settings.json.
| Key | Type | Default | Description |
|---|---|---|---|
gateway_uri |
string |
ws://your_host:18789 |
Active gateway WebSocket URI |
auth_token |
string |
your_token |
Bearer token for gateway authentication |
agent_id |
string |
wabot |
Target agent identifier |
session_key |
string |
agent:wabot:solace |
Active session key |
tts_speed |
double |
0.5 |
TTS playback speed (0.0 – 1.0) |
tts_enabled |
bool |
false |
Enable/disable text-to-speech |
default_voice_mode |
bool |
false |
Start in voice mode by default |
show_system_messages |
bool |
true |
Show system/tool messages in chat |
font_size |
double |
14.5 |
Chat font size |
gateway_hosts |
string[] |
(see Config.cs) | Ordered list of fallback gateway hosts |
| File | Description |
|---|---|
<AppDataDirectory>/device_key.bin |
Raw 32-byte Ed25519 private key (generated once) |
<AppDataDirectory>/device_token.json |
Signed device token for gateway registration |
⚠️ Do not deletedevice_key.bin— doing so generates a new identity and requires re-registration with the gateway.
┌─────────────────────────────┐
│ MAUI UI Layer │
│ ChatPage / ChatListPage / │
│ SettingsPage / … │
└────────────┬────────────────┘
│
┌────────────▼────────────────┐
│ K2Service │
│ (business logic, TTS, │
│ shell execution) │
└────────────┬────────────────┘
│
┌────────────▼────────────────┐
│ GatewayClient │
│ (WebSocket, OpenClaw │
│ protocol, event streams) │
└────────────┬────────────────┘
│ ws://
┌────────────▼────────────────┐
│ OpenClaw Gateway Server │
│ (self-hosted, port 18789) │
└─────────────────────────────┘
An Android foreground service (K2BackgroundService) maintains the WebSocket connection when the app is not in the foreground. It posts a persistent notification while connected and fires message notifications for new agent responses.
When voice mode is active:
AudioCaptureopens Android'sSpeechRecognizerin continuous mode- RMS energy values animate the SkiaSharp orb in real time
- Final transcriptions are sent to the gateway as user messages
- Agent responses are optionally spoken back via TTS
Voice mode can be toggled with the microphone button in the chat toolbar or enabled by default via settings.
K2 communicates with the gateway using a JSON-over-WebSocket protocol:
- Authentication — Connects with
auth_token; registers with a signed Ed25519 device token on first connection - Session routing — Messages are routed to the agent via
session_key(format:agent:<agentId>:<username>) - Streaming — Agent responses stream token-by-token via
agent_textevents, completed byagent_done - Tool calls — The agent can invoke tools; K2 surfaces these as system messages and optionally executes approved shell commands
dotnet publish -f net9.0-android -c ReleaseSign the resulting APK/AAB with your keystore before distribution.
The following Android permissions are declared:
| Permission | Reason |
|---|---|
INTERNET |
WebSocket connection to the gateway |
RECORD_AUDIO |
Voice mode / speech recognition |
FOREGROUND_SERVICE |
Background WebSocket service |
POST_NOTIFICATIONS |
Message notifications (Android 13+) |
This project is private. All rights reserved.