Zum Inhalt

Hinweis: Diese Inhalte wurden mit Unterstützung von Künstlicher Intelligenz erstellt und redaktionell überprüft (Transparenzhinweis gemäß Art. 50 EU AI Act).

Android-KI-Agent-Fernsteuerung für den lokalen PC selbst programmieren (Kotlin & KI-Agent-SDK)

Die Fernsteuerungs-Topliste für den lokalen Rechner stellt fertige Open-Source-Apps vor. Diese Seite geht den anderen Weg: eine eigene Android-App in Kotlin, die über eine selbst geschriebene Backend-Schicht einen KI-Agenten auf dem heimischen PC fernsteuert. Das Backend übernimmt die eigentliche Agenten-Logik (z. B. mit dem Claude Agent SDK oder der Claude API), die Kotlin-App ist ein schlanker Client, der per LAN oder VPN mit diesem Backend spricht.

Hinweis: Warum ein Backend nötig ist

Es gibt kein offizielles Kotlin-/Android-SDK für Claude. Die Anthropic-SDKs existieren für Python, TypeScript, Java/Kotlin (JVM), Go, Ruby, C# und PHP — aber Java/Kotlin bedeutet hier JVM-Server, nicht Android. Die Android-App ruft daher nie direkt die Anthropic-API auf, sondern ausschließlich eine eigene HTTP-/WebSocket-Schnittstelle auf dem PC. Das ist zugleich der einzig sichere Weg: Ein API-Key, der in einer APK eingebettet ist, lässt sich durch Dekompilieren extrahieren.


Architektur-Überblick

graph TD
    App["Android-App (Kotlin, Jetpack Compose)"] -->|"HTTPS / WebSocket über LAN oder Tailscale"| Backend["Backend-Prozess auf dem PC (Python oder TypeScript)"]
    Backend -->|"Claude Agent SDK oder Claude API + Tool Use"| Agent["Agenten-Loop"]
    Agent -->|"Tools: Bash, Datei-I/O, lokale Skripte"| PC["Lokaler Rechner"]
    Agent -->|"Messages API"| Claude["Claude (Anthropic API)"]

Drei Bausteine, drei Verantwortlichkeiten:

Baustein Sprache/Technologie Aufgabe
Android-App Kotlin, Jetpack Compose, Ktor Client oder OkHttp Chat-UI, sendet Prompts, zeigt Streaming-Antworten
Backend-Prozess Python (claude-agent-sdk) oder TypeScript (@anthropic-ai/claude-agent-sdk) Hält den API-Key, betreibt den Agenten-Loop, exponiert eine eigene REST-/WebSocket-Schnittstelle
Claude Anthropic API Denkt, plant, ruft Tools auf

Achtung: Claude Agent SDK ist kein Server

Das Claude Agent SDK (claude-agent-sdk / @anthropic-ai/claude-agent-sdk) ist Claude Code als Bibliothek — es liefert die Agenten-Schleife samt eingebauten Tools (Datei-Lesen/Schreiben, Bash, Web-Suche), aber keine HTTP-Schnittstelle nach außen. Diese Schicht (FastAPI, Express, Ktor auf JVM-Seite) muss selbst geschrieben werden. Alternativ eignet sich ein manueller Agenten-Loop direkt auf der Claude API mit Tool Use, wenn nur ein festes, kleines Tool-Set benötigt wird.


Backend: Agenten-Prozess auf dem PC

Der Backend-Prozess läuft dauerhaft auf dem PC (z. B. als systemd-User-Service oder in tmux) und übersetzt eingehende HTTP-/WebSocket-Anfragen der Android-App in Aufrufe des Claude Agent SDK.

from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from claude_agent_sdk import query, ClaudeAgentOptions

app = FastAPI()

@app.post("/chat")
async def chat(prompt: str):
    options = ClaudeAgentOptions(
        cwd="/home/user/projekt",
        allowed_tools=["Read", "Write", "Bash"],
    )

    async def event_stream():
        async for message in query(prompt=prompt, options=options):
            yield f"data: {message}\n\n"

    return StreamingResponse(event_stream(), media_type="text/event-stream")
import express from "express";
import { query } from "@anthropic-ai/claude-agent-sdk";

const app = express();
app.use(express.json());

app.post("/chat", async (req, res) => {
  res.setHeader("Content-Type", "text/event-stream");

  for await (const message of query({
    prompt: req.body.prompt,
    options: { cwd: "/home/user/projekt", allowedTools: ["Read", "Write", "Bash"] },
  })) {
    res.write(`data: ${JSON.stringify(message)}\n\n`);
  }
  res.end();
});

app.listen(8765);

Der Anthropic-API-Key steckt ausschließlich in der Umgebung dieses Prozesses (ANTHROPIC_API_KEY bzw. ant auth login) — die Android-App bekommt ihn nie zu Gesicht.


Kotlin-Android-App: Client für das eigene Backend

Die App braucht nur einen HTTP-Client mit Streaming-Unterstützung (Server-Sent Events oder WebSocket) und eine Chat-Oberfläche. Ktor Client eignet sich für beides in einer gemeinsamen Kotlin-Codebasis.

// build.gradle.kts (Module: app)
dependencies {
    implementation("io.ktor:ktor-client-core:2.3.12")
    implementation("io.ktor:ktor-client-cio:2.3.12")
    implementation("io.ktor:ktor-client-content-negotiation:2.3.12")
}
class AgentClient(private val baseUrl: String) {
    private val client = HttpClient(CIO)

    suspend fun streamChat(prompt: String, onEvent: (String) -> Unit) {
        client.preparePost("$baseUrl/chat") {
            contentType(ContentType.Application.Json)
            setBody(mapOf("prompt" to prompt))
        }.execute { response ->
            val channel: ByteReadChannel = response.bodyAsChannel()
            while (!channel.isClosedForRead) {
                val line = channel.readUTF8Line() ?: continue
                if (line.startsWith("data: ")) onEvent(line.removePrefix("data: "))
            }
        }
    }
}

In der Compose-UI wird streamChat aus einer ViewModel-viewModelScope.launch { }-Coroutine aufgerufen; jedes empfangene Event hängt sich an eine mutableStateListOf<String> an, die die Chat-Bubbles rendert.

Tipp: WebSocket statt SSE bei bidirektionaler Steuerung

Server-Sent Events reichen für reines "Prompt rein, Antwort-Stream raus". Soll die App den Agenten mitten im Lauf unterbrechen können (Bash-Bestätigung, Abbruch), ist ein WebSocket (ktor-client-websockets) die bessere Wahl — dann lässt sich in beide Richtungen senden, ohne eine zweite Verbindung aufzumachen.


Kommunikationsprotokoll

Protokoll Eignung Bibliothek (Kotlin)
REST + Server-Sent Events Einfacher Chat, ein Request pro Prompt Ktor Client (preparePost + bodyAsChannel)
WebSocket Bidirektional: Unterbrechen, Tool-Bestätigungen, Live-Status ktor-client-websockets oder OkHttp WebSocketListener
Reine REST-Polling-API Am einfachsten zu debuggen, aber kein Echtzeit-Feedback Retrofit + suspend fun

Erreichbarkeit & Sicherheit

graph TD
    Start{"Wie soll das Handy den PC erreichen?"} -->|"Nur im Heim-WLAN"| A["Backend an 0.0.0.0:8765 binden, lokale Firewall-Regel"]
    Start -->|"Auch von unterwegs"| B["Tailscale/WireGuard auf PC + Handy, Backend nur an Tailscale-IP binden"]
    B --> C["Zusätzlich: Bearer-Token in jedem Request prüfen"]
    A --> C

Achtung: Niemals ungeschützt ins offene Netz

Das selbstgebaute Backend hat i. d. R. keine eingebaute Authentifizierung. Mindestens ein statisches Bearer-Token (per Authorization-Header, serverseitig gegen eine Umgebungsvariable geprüft) einbauen, bevor der Port über den Router nach außen freigegeben wird — besser: gar nicht freigeben, sondern ausschließlich über Tailscale erreichbar machen, wie in der Fernsteuerungs-Topliste beschrieben.

Für den Ablauf "Wake-on-LAN, wenn der PC im Schlafmodus ist" gilt dieselbe Einschränkung wie bei den fertigen Apps aus der Topliste — ein Agenten-Backend, das nicht läuft, ist nicht erreichbar.


Verwandte Themen

Hinweis: Diese Inhalte wurden mit Unterstützung von Künstlicher Intelligenz erstellt und redaktionell überprüft (Transparenzhinweis gemäß Art. 50 EU AI Act).