Introduction
Martyrun is an AI-powered Android automation platform. Connect your devices over USB or Wi-Fi, define task sequences, and let the LLM engine handle TikTok interactions — warmups, posting, follows, likes — without a single hardcoded XPath.
Quickstart
Connect a device and run your first warmup in 5 steps.
Make sure Python 3.10+, ADB, and the required packages are installed.
pip install groq customtkinter requests fastapi uvicorn
Go to Settings → About Phone, tap Build Number 7 times to unlock Developer Options, then enable USB Debugging.
Samsung devices: go to Settings → General Management → Software Info to find Build Number.
adb devices # Expected output: # List of devices attached # XXXXXXXX device
Create a free account at console.groq.com and get your API key. Add it in Settings inside the app, or set it as an environment variable:
export GROQ_API_KEY=gsk_xxxxxxxxxxxxxxxxxxxx
python marty.py
In the GUI, navigate to Devices, select your device, and click Start Warmup.
Installation
Martyrun runs as a local Python app. You can also expose the cloud dashboard via the built-in FastAPI server.
Requirements
Python >= 3.10 Android Debug Bridge (adb) in PATH Groq account (free tier works) Android device with USB Debugging enabled
Clone and run
git clone https://github.com/martyrun/martyrun cd martyrun pip install -r requirements.txt python marty.py # desktop GUI # or python marty_cloud.py # cloud dashboard (port 8000)
Devices
Martyrun discovers Android devices automatically via ADB. Each device runs its task queue independently in a background thread.
Wi-Fi ADB: run adb tcpip 5555 then adb connect DEVICE_IP:5555 to connect wirelessly.
Device status
| Status | Description |
|---|---|
| online | Device connected and idle |
| running | Task currently executing |
| offline | ADB connection lost |
Tasks
Tasks are defined in tiktok-data/tasks.json. Each device has a list of tasks that run in sequence.
{
"devices": [
{
"serial": "XXXXXXXX",
"account": "@myaccount",
"tasks": [
{ "type": "warmup", "config": "default" },
{ "type": "post", "video": "video_001", "config": "post_default" },
{ "type": "sleep", "min": 30, "max": 60 }
]
}
]
}
Task types
| Type | Description |
|---|---|
| warmup | Browse TikTok FYP, like/save/follow/comment based on config probabilities |
| post | Push a video to device and upload it to TikTok with caption |
| sleep | Wait a random duration between min and max minutes |
Configs
Configs live in tiktok-data/configs.json and control warmup and post behavior.
{
"warmupConfigs": {
"default": {
"warmup_time": 15,
"like_prob": 30,
"fav_prob": 5,
"follow_prob": 10,
"max_follows": 3,
"browse_comments_prob": 20
}
},
"postConfigs": {
"post_default": {
"sound_option": "original",
"caption_template": "Check this out! #fyp #viral"
}
}
}
Automation Engine
The Martyrun engine uses a Perception → Reason → Action loop powered by Groq's LLM — no XPaths, no hardcoded selectors.
adb -s {serial} shell uiautomator dump /sdcard/ui.xml
adb -s {serial} pull /sdcard/ui.xml /tmp/ui.xml
The XML is parsed into a compact element list (text, bounds, clickable) and sent alongside a screenshot to Llama 4 Scout with the current goal and last 8 actions.
The LLM returns a structured JSON action: {"action":"tap","x":540,"y":1200,"reason":"..."}
adb shell input tap 540 1200 adb shell input text "hello" adb shell input swipe 540 1600 540 400 300 adb shell input keyevent 4 # back
If the same UI tree appears 3 times in a row, Martyrun automatically presses Back and retries with a fresh context.
API Reference — Devices
Base URL: http://localhost:8000
[
{
"serial": "XXXXXXXX",
"status": "running",
"account": "@myaccount",
"liked": 12,
"saved": 3,
"followed": 1
}
]
| Param | Type | Required | Description |
|---|---|---|---|
| serial | string | required | ADB device serial number |
Gracefully stops the current task and clears the queue.
API Reference — Tasks
Returns the full contents of tiktok-data/tasks.json.
Send a JSON body matching the tasks schema. Persisted to disk immediately.
WebSocket
Connect to the live log stream for real-time device activity.
const ws = new WebSocket('ws://localhost:8000/ws/logs');
ws.onmessage = (e) => {
const msg = JSON.parse(e.data);
// { serial, level, text, ts }
console.log(msg.serial, msg.text);
};
| Field | Type | Description |
|---|---|---|
| serial | string | Device serial or "system" |
| level | string | info | warn | error | success |
| text | string | Log message |
| ts | number | Unix timestamp (ms) |
Changelog v0.1
| Version | Changes |
|---|---|
| v0.1.0 | Initial release — LLM engine, warmup, post, cloud dashboard, Supabase auth |