Repository navigation
runcode v1.0.0 — real CPython, working web server, shell and MCP bridge
runcode v1.0.0
An on-device Android runtime: real CPython, a working local web server, a shell, and an
authenticated MCP bridge so an AI client can drive the whole thing.
Tested on Android 16 (API 36). minSdk 26.
Highlights
Real Python. CPython 3.12 is embedded via Chaquopy. Scripts run as __main__ with the
project directory as the working directory, so relative paths like data/tasks.sqlite
resolve the way they do on a desktop. Output streams into the console line by line while the
script runs, and a long-running loop can be interrupted from the UI or over MCP.
A local web server that works. Static web projects are served by a built-in HTTP/1.1
server with correct content types, SPA fallback and directory-escape protection.
A shell. Interactive /system/bin/sh inside the app sandbox, with the selected project's
directory as cwd and its environment injected. No root, no PTY, no job control — it is the
shell every Android device already ships.
MCP bridge. JSON-RPC 2.0 over POST /mcp, protocol revision 2025-06-18, twelve tools:
list_projects · get_project · list_files · read_file · write_file ·
start_service · stop_service · service_status · get_logs · run_command ·
run_python · sql_query
Point any MCP client at it:
adb forward tcp:8765 tcp:8765
curl -s -X POST http://127.0.0.1:8765/mcp \
-H "Authorization: Bearer $RUNCODE_TOKEN" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'Security
The bridge exposes a shell, arbitrary Python and read/write file access, so:
- a bearer token is required on every call including on loopback, compared in constant time;
- the token is 24 random bytes kept in an Android Keystore-backed vault and rotatable from
the UI; - the listener binds
127.0.0.1unless LAN exposure is explicitly enabled; - secret-valued environment variables are returned as
<secret>, never echoed; GET /healthis the only unauthenticated route and reveals nothing about the device;- the process is held in the foreground while the bridge is online.
The secret vault itself now uses an Android Keystore key with a random IV per value, and
refuses to store a value it cannot encrypt. Backup rules no longer ship the vault to cloud
backup.
Backup archives are checksum-verified for real. The screen always claimed they were;
nothing was ever compared. Both Verify and Restore now refuse an archive whose payload does
not hash to the value in its manifest.
Fixes
- A fresh clone could not build: the signing config pointed at a
debug.keystorethat was
not in the repo. There is now a Gradle wrapper and a.gitignoreas well. - Static web projects crashed the app with
NoClassDefFoundErroron
com.sun.net.httpserver, which exists in the JDK but not on Android. - Every log line crashed the app on Android 8–13:
Matcher.replaceAll(Function)is API 34+
and was called on each line withminSdk 26.FOREGROUND_SERVICE_TYPE_SPECIAL_USEhad the
same problem. - A script that finished successfully was reported as
FAILED. - A port conflict picked a free port, logged it, then bound the occupied one anyway.
- The wake lock was re-acquired on every automatic restart and never released.
- Environment variables, arguments and the working directory were not persisted, so a
configured Telegram bot token vanished on restart. - The bottom navigation could not fit its destinations and wrapped labels mid-word.
- On the Backups screen the Restore button was pushed off the right edge by long archive
names and could not be tapped, and a failed verification showed no reason.
Android lint: 11 errors → 0.
Known limitations
pippackages are not enabled; third-party libraries need a build-time requirements list
in thechaquopy { }block.- JavaScript and PHP runtimes are not implemented and are labelled as such in the UI.
- The MCP bridge lives in the app process and does not survive the process being killed.
- The APK is ~52 MB because CPython ships for
arm64-v8aandx86_64. Trimming
abiFiltersto a single ABI roughly halves it.
Install
runcode-v1.0.0.apk is signed with a 4096-bit RSA key (APK Signature Scheme v2 + v3),
minSdk 26, ABIs arm64-v8a and x86_64. Sideload it — this is not on any store, so your
device will ask you to allow installation from an unknown source.
Licensed MIT.