ai newsFr., 23. Okt.

Claude auf dem Nokia 3310: J2ME-Client mit 41 mitgelieferten Spielen

Ein Entwickler hat VibeNokia gebaut, einen Java-ME-Client, der das Feature Phone von 2017 in ein Chat-Terminal für Claude verwandelt. Ein FastAPI-Server speichert den Verlauf und prüft Signaturen, dazu gibt es Telegram, Sprachnachrichten und 41 Mini Games.

dev.toFreitag 03:42 · 23.10.DE5 Min. Lesezeit
Bild: dev.to

Ich habe VibeNokia geschrieben: einen Java-ME-Client für das Nokia-3310-Feature-Phone von 2017, der es in ein Chat-Terminal für Claude verwandelt, dazu einen kleinen FastAPI-Server, der den Verlauf speichert, Signaturen prüft und claude -p ausführt. Das Menü bietet außerdem Telegram, Sprachnachrichten und einen Katalog mit 41 Mini-Spielen. Es funktioniert auf meinem physischen Telefon, und dabei musste ich etliche Dinge neu lösen, die ein Smartphone mit einem einzigen Bibliotheksaufruf bekommt.

Ein Hinweis vorab: Der Client wurde auf einem echten Nokia 3310 (TA-1030) getestet. Andere Series-30+- oder Series-40-Telefone habe ich nicht ausprobiert. Der Kanal zwischen Telefon und Server ist nicht verschlüsselt; dazu unten mehr, ohne etwas zu beschönigen.

Das Nokia 3310 von 2017 nutzt Series 30+ auf einem MediaTek MT6260. Es läuft mit Java ME unter CLDC 1.1 / MIDP 2.0, hat einen 240x320-Bildschirm, nur mobile Daten und kein WLAN. Es gibt keinen brauchbaren Browser und keinen App Store. Eine einfache HttpConnection mit POST und JSON funktioniert tatsächlich (das habe ich auf meinem Gerät gesehen), und der Akku hält eine Woche.

Das Design ist daher schlank gehalten: Das Telefon führt einen Client aus, der den Bildschirm zeichnet und Anfragen sendet, während mein Server die gesamte schwere Arbeit übernimmt. Die App lässt sich als.jad/.jar-Paar von der Speicherkarte oder over the air installieren: Der Server stellt die Dateien selbst unter /ota/VibeNokia.jad bereit.

docs/platform-notes.md sammelt Beobachtungen, die ich vor dem Start gern gehabt hätte. Die Punkte, die mich Zeit gekostet haben:

An dieser Stelle bin ich an eine Grenze gestoßen. Laut öffentlichen Quellen endet der Java-Stack in diesen Telefonen bei alten TLS-Versionen und einem alten Zertifikatsspeicher, sodass moderne HTTPS-URLs nicht geöffnet werden können. In meinen Notizen ist das als "berichtet" markiert: Ich habe es auf meinem eigenen Gerät nicht bewusst erneut verifiziert. Für das Projekt ist das Ergebnis ohnehin dasselbe: Der Client verwendet einfaches HTTP.

Das bedeutet, dass man sich nicht auf Kanalgeheimnis verlassen kann, weshalb die App so gebaut ist, dass sie nicht davon abhängt. Daher die signierten Anfragen.

Das Telefon wird einmalig mit dem Server gekoppelt und erhält einen eigenen Schlüssel. Danach verlässt der Schlüssel nie das Netzwerk. Jede Anfrage trägt einen HMAC-SHA256, der berechnet wird über:

Der Server prüft die Signatur und den Zähler. Eine wiedergespielte Anfrage wird verworfen: Ein Fenster der 64 zuletzt verwendeten Zähler funktioniert wie das Sliding Window in IPsec. Die Signatur schließt die Serveradresse ( VIBENOKIA_PUBLIC_HOST ) ein, sodass eine für eine andere Adresse signierte Anfrage abgelehnt wird. Wiederholt falsche Signaturen oder Codes führen dazu, dass die Quelle für 15 Minuten gesperrt wird.

Das Pairing funktioniert so. Man setzt VIBENOKIA_PAIRING=1 in.env. Auf dem Telefon drückt man 5, und der Server schreibt einen einmaligen sechsstelligen Code in data/pair_code.txt (Modus 600); wenn ein Telegram-Token und mein Chat konfiguriert sind, wird der Code auch dorthin gesendet. Der Code gilt 10 Minuten und funktioniert nur einmal. Man tippt ihn auf dem Telefon ein, das Gerät erhält seinen Schlüssel und speichert ihn. Danach setzt man VIBENOKIA_PAIRING=0, und die Pfade /pair/* antworten mit 404. Ein Telefon kann lokal mit tools/devices.py gegen die Datenbankdatei widerrufen werden; eine Netzwerk-Admin-API gibt es bewusst nicht.

Die Signatur schützt vor Fälschung, Raten und Replay. Sie schützt überhaupt nicht vor Mithören. Jeder auf dem Weg zwischen Telefon und Server kann deine Fragen und Claudes Antworten lesen. Man sollte von diesem Telefon nichts Geheimes senden. Ich sage das im README und in den Deployment-Dokumenten und wiederhole es hier, weil es schlimmer ist, wenn Menschen solche Dinge selbst herausfinden.

Der Server ist Python mit FastAPI und SQLite: Sitzungen, Geräte und Kontakte liegen in einer Datei. Zum Antworten führt er claude -p mit einem kurzen Systemprompt aus, der für einen winzigen Bildschirm geschrieben wurde. Wichtig ist:

Bevor der Port geöffnet wird, gibt es in der Dokumentation eine kurze Prüfung: ss -ltn | grep -v 127.0.0.1 sollte nur den Proxy-Port zeigen, und curl gegen /ping und /api/chat ohne Signatur sollte 403 und niemals 200 zurückgeben.

Die erste Version startete mit allen Funktionen auf einmal. In der zweiten (v0.2.0) beginnt die App mit einem einfachen Menü aus zwei Kacheln: Chat mit Claude und Einstellungen. Alles andere (Telegram, Sprache, Sitzungen, eine zweite Kachel für OpenCode und die Gruppe "Erweitert": Serverliste, In-App-Update, Schlüsselrotation) wird in Einstellungen > Funktionen eingeschaltet. Die Auswahl wird im RMS-Speicher des Telefons abgelegt. Die serverseitige Obergrenze kommt obendrauf zum Tragen: Eine Funktion, die der Server verbietet, ist in der App ausgeblendet, und die Liste trifft in der /ping-Antwort ein. Beim Upgrade von einer älteren Version bleibt alles sichtbar, was zuvor sichtbar war, während eine frische Installation einfach startet.

Immer verfügbar: Chat, Modellwahl (Opus, Sonnet oder Haiku), neuer Chat, Sprache (Russisch oder Englisch) und Schriftgröße. Die Kacheln sind in der angezeigten Reihenfolge nummeriert, die Ziffer öffnet eine Kachel, und 5 öffnet die ausgewählte. Mit gedrückter Stern-Taste kann man diktieren: Die Aufnahme geht an den Server, wird dort transkribiert (Gemini über OpenRouter, Groq Whisper als Fallback) und landet im Chat.

Die Screenshots stammen aus MicroEmulator bei 240x320.

Der Katalog enthält 41 eigenständige Apps ohne Berechtigungen und ohne Netzwerk. Neun davon wurden in diesem Repository geschrieben; die anderen 32 sind MIT-lizenzierte Spiele aus dem Archiv agneay/j2me-100-games. Drittkomponenten sind in THIRD_PARTY_NOTICES.md aufgeführt. Ein Skript, scripts/build-games.sh, baut sie alle.

Man braucht Docker mit Compose, make und entweder einen Claude-API-Key oder eine Claude-Code-Anmeldung:

git clone https://github.com/meshoklv/vibenokia && cd vibenokia./scripts/quickstart.sh # erstellt.env mit einem frischen Schlüssel und startet den Server auf 127.0.0.1:8085 make -C client SERVER_URL = http://your.host:8080 # -> client/dist/VibeNokia.jar + VibeNokia.jad./scripts/build-games.sh # optional -> games/dist/ Enter fullscreen mode Exit fullscreen mode Der Client wird in einem öffentlichen Docker-Image mit einer J2ME-Toolchain gebaut. Man installiert VibeNokia.jad von der Speicherkarte und koppelt dann wie oben beschrieben mit einem Code. Ohne Docker läuft der Server mit scripts/run-local.sh; dann braucht man Python 3.10+, ffmpeg für Sprache und claude auf dem PATH.

Getestet: der Client auf einem echten Nokia 3310. Für diese Version bauen der Client und alle 41 Spiele im J2ME-Container, und das neue Menü sowie den Funktionen-Bildschirm habe ich von Hand in MicroEmulator durchgeklickt (die Screenshots stammen von dort). Das Server-Image baut und antwortet mit 403 auf Loopback ohne Authentifizierung, und Pairing sowie signierter Chat wurden End-to-End mit dem Telefonemulator und einem Stub an Stelle von claude durchgespielt.

Nicht getestet: ein echter Claude-Aufruf innerhalb des veröffentlichten Docker-Images, andere Series-30+- und Series-40-Telefone und ein TLS-Frontend zusammen mit dem Telefon. Geplant: vorgebaute.jar-Dateien in den Releases und gerätespezifische Tool-Allow-Lists.

Ein Teil des Codes wurde zusammen mit einem KI-Assistenten (Claude) geschrieben; der Commit-Verlauf zeigt dies über eine Co-Authored-By-Zeile.

Repository: github.com/meshoklv/vibenokia, MIT-Lizenz. Issues und PRs sind offen; die Regeln stehen in CONTRIBUTING.md. Wenn du ein anderes J2ME-Telefon hast und es ausprobierst, erzähl mir, was passiert ist. Ich veröffentliche Notizen auf Telegram unter t.me/meshoklv.

Automatisch übersetzt. Das Original auf Englisch ist unten aufklappbar.

Original (Englisch) anzeigen

I wrote VibeNokia: a Java ME client for the 2017 Nokia 3310 feature phone that turns it into a chat terminal for Claude, plus a small FastAPI server that stores history, verifies signatures and runs claude -p. The menu also has Telegram, voice messages and a catalogue of 41 mini games. It works on my physical phone, and along the way I had to re-solve several things that a smartphone gets from a one-line library call.

A caveat up front: the client has been tested on one real Nokia 3310 (TA-1030). I haven't tried other Series 30+ or Series 40 phones. The channel between the phone and the server is not encrypted; more on that below, without softening it.

The 2017 Nokia 3310 is Series 30+ on a MediaTek MT6260. It runs Java ME with CLDC 1.1 / MIDP 2.0, has a 240x320 screen, mobile data only and no Wi-Fi. It has no usable browser and no app store. A plain HttpConnection with POST and JSON does work (I've seen this on my device), and the battery lasts a week.

So the design is thin: the phone runs a client that draws the screen and sends requests, and my server does all the heavy work. The app installs as a.jad/.jar pair from the memory card, or over the air: the server itself serves the files at /ota/VibeNokia.jad.

docs/platform-notes.md collects observations I wish I'd had before starting. The ones that cost me time:

This is where I hit a wall. According to public sources, the Java stack in these phones stops at old TLS versions and an old certificate store, so modern HTTPS URLs don't open. In my notes this is marked "reported": I did not deliberately re-verify it on my own device. The outcome for the project is the same either way: the client uses plain HTTP.

That means you can't rely on channel secrecy, so the app is built not to depend on it. Hence signed requests.

The phone is paired with the server once and receives its own key. After that the key never crosses the network. Every request carries an HMAC-SHA256 computed over:

The server checks the signature and the counter. A replayed request is dropped: a window of the 64 most recent counters works like the sliding window in IPsec. The signature includes the server address ( VIBENOKIA_PUBLIC_HOST ), so a request signed for a different address is rejected. Repeated wrong signatures or codes get the source banned for 15 minutes.

Pairing works like this. Set VIBENOKIA_PAIRING=1 in.env. Press 5 on the phone, and the server writes a one-time six-digit code to data/pair_code.txt (mode 600); if a Telegram token and my chat are configured, the code is also sent there. The code lives for 10 minutes and works once. You type it on the phone, the device gets its key and stores it. Then you set VIBENOKIA_PAIRING=0 and the /pair/* paths answer 404. A phone can be revoked locally with tools/devices.py against the database file; there is deliberately no network admin API.

Signing protects against forgery, guessing and replay. It does not protect against eavesdropping at all. Anyone on the path between the phone and the server can read your questions and Claude's answers. Don't send anything secret from this phone. I say this in the README and in the deployment docs and repeat it here, because it's worse when people discover such things themselves.

The server is Python with FastAPI and SQLite: sessions, devices and contacts live in one file. To answer, it runs claude -p with a short system prompt written for a tiny screen. What matters:

Before opening the port, the docs have a short check: ss -ltn | grep -v 127.0.0.1 should show only the proxy port, and curl against /ping and /api/chat without a signature should return 403 and never 200.

The first version opened with every feature at once. In the second (v0.2.0) the app starts with a simple menu of two tiles: chat with Claude, and Settings. Everything else (Telegram, voice, sessions, a second tile for OpenCode, and the "advanced" group: server list, in-app update, key rotation) is switched on in Settings > Features. The choice is kept in the phone's RMS storage. The server-side ceiling is applied on top: a feature the server forbids is hidden in the app, and the list arrives in the /ping reply. Upgrading from an older version keeps everything that was visible before, while a fresh install starts simple.

Always available: chat, model choice (Opus, Sonnet or Haiku), new chat, language (Russian or English) and font size. Tiles are numbered in the order shown, the digit opens a tile, and 5 opens the selected one. Hold * to dictate: the recording goes to the server, is transcribed there (Gemini via OpenRouter, Groq Whisper as a fallback) and lands in the chat.

The screenshots are from MicroEmulator at 240x320.

The catalogue has 41 standalone apps with no permissions and no network. Nine were written in this repository; the other 32 are MIT-licensed games from the agneay/j2me-100-games archive. Third-party components are listed in THIRD_PARTY_NOTICES.md. One script, scripts/build-games.sh, builds them all.

You need Docker with Compose, make, and either a Claude API key or a Claude Code login:

git clone https://github.com/meshoklv/vibenokia && cd vibenokia./scripts/quickstart.sh # creates.env with a fresh key and starts the server on 127.0.0.1:8085 make -C client SERVER_URL = http://your.host:8080 # -> client/dist/VibeNokia.jar + VibeNokia.jad./scripts/build-games.sh # optional -> games/dist/ Enter fullscreen mode Exit fullscreen mode The client builds inside a public Docker image with a J2ME toolchain. Install VibeNokia.jad from the memory card, then pair with a code as described above. Without Docker the server runs with scripts/run-local.sh; you then need Python 3.10+, ffmpeg for voice and claude on PATH.

Tested: the client on a real Nokia 3310. For this release the client and all 41 games build in the J2ME container, and I drove the new menu and Features screen by hand in MicroEmulator (the screenshots come from there). The server image builds and answers 403 on loopback without auth, and pairing plus signed chat were exercised end to end with the phone emulator and a stub in place of claude.

Not tested: a real Claude call inside the published Docker image, other Series 30+ and 40 phones, and a TLS front together with the phone. Planned: prebuilt.jar files in releases and per-device tool allow-lists.

Part of the code was written together with an AI assistant (Claude); the commit history shows this through a Co-Authored-By line.

Repository: github.com/meshoklv/vibenokia, MIT license. Issues and PRs are open; the rules are in CONTRIBUTING.md. If you have another J2ME phone and try it, tell me what happened. I post notes on Telegram at t.me/meshoklv.

Originaltitel: Claude on a Nokia 3310: a J2ME client, HMAC instead of TLS, and 41 bundled gamesQuelle: dev.to (dev.to). Original öffnen