7.1 KiB
7.1 KiB
MASTER PROMPT — Android Fleet Godhead (complete rebuild spec)
You are an expert systems architect, network engineer, and full-stack developer. Rebuild the ANDROID FLEET GODHEAD: an autonomous Android VM fleet controller for Proxmox.
REAL INFRASTRUCTURE (do not invent alternatives)
- Proxmox host 10.30.20.85 (SSH root, key auth; API https://10.30.20.85:8006/api2/json, token
PVEAPIToken root@pam!androidcloud=d324351f-5c70-45a1-855f-3552bd290bc1, verify_ssl=False). Node name: pve. - SINGLE bridge
vmbr0= LAN 10.30.20.0/24, Xfinity router at 10.30.20.1 handles DHCP (dynamic pool .100-.254). THERE IS NO vmbr1, NO dnsmasq — do NOT build one. Android VMs DHCP on the existing LAN. - Android template: VM 1301, Android-x86 9.0-r2, 4 cores / 6GB / 12GB qcow2 (storage
local, content types iso,vztmpl,backup,rootdir,images). Boot args (per-clone, unique -vnc display XX):-kernel /var/lib/vz/template/kernel -initrd /var/lib/vz/template/initrd.img -append "quiet root=/dev/ram0 androidboot.hardware=android_x86_64 SRC=/android-9.0-r2 androidboot.selinux=permissive SETUPWIZARD=0 ip=dhcp" -vnc 0.0.0.0:59XX,password=off - Template is backdoored:
ro.adb.secure=0+service.adb.tcp.port=5555in build.prop AND an /system/etc/init.sh hook that re-issues setprop + restarts adbd at boot. system.sfs inside the ext2 disk at /android-9.0-r2/system.sfs — when rebuilding it: mksquashfs MUST use-comp gzip -b 131072(xz/256K makes this kernel hang at "Detecting Android-x86"). The sfs wraps a singlesystem.img(ext4) — edit build.prop/init.sh by loop-mounting it. - Each clone gets a random MAC -> random DHCP IP -> adb open on 5555 (insecure, root).
- Control node: LXC CT 704
android-fleet-godhead@ 10.30.20.31:8080, Debian 12, Python 3.11, Flask + flask-sock + SQLite + adb + requests + pysocks. systemd unitandroid-fleet.service, WorkingDirectory /opt/android-fleet. SSH key from CT704 → Proxmox authorized_keys (forip neighARP). - Proxy pool: local NordVPN SOCKS5 containers running gost
-L socks5://0.0.0.0:1080— CT680 nord-tunnel 10.30.20.154, CT681 nord-london 10.30.20.71, CT682 nord-sydney 10.30.20.189. Each device gets ONE proxy → unique egress IP. Assign viaadb shell settings put global http_proxy host:port+settings put global global_http_proxy host:port. - AI automation: Hermes agents on local GPU Ollama ONLY — light_reaper 10.30.20.186:11434 (granite4.1:3b agentic) or shadow-death 10.30.20.128:11434 (gemma4:26b heavy). NEVER MacBook models, NEVER run LLMs inside Proxmox CTs. LLM calls: POST /api/chat with {"model", "keep_alive": "30m", "messages", "stream": false, "options": {"num_predict": ...}} — big models need num_predict >= 2048 (thinking tokens are uncapped), never instruct them to "hide reasoning" (infinite loop).
ARCHITECTURE
Proxmox (10.30.20.85) ──clone/start/destroy──▶ CT704 android-fleet-godhead (10.30.20.31:8080)
│
vmbr0 LAN 10.30.20.0/24 ──────────────────────┤
│
android clones (VMIDs 1310+, DHCP IPs, adb :5555) ◀─── scan + adb + metrics
nord CTs (680/681/682 gost :1080) ◀─── proxy health + per-device assignment
COMPONENTS
1. Discovery (every 10s)
- Threaded port scan of 10.30.20.0/24 for open :5555 (socket timeout 1.0s, 64-256 threads).
- For each open IP:
adb connect ip:5555thenadb shell cat /sys/class/net/eth0/address= MAC (primary). Fallback:ssh root@10.30.20.85 ip neigh show dev vmbr0(host ARP only shows IPs the HOST has talked to — never rely on it alone). - vmid resolution: match MAC against Proxmox
net0configs of qemu VMs. - Register new MAC → DEVICE_JOINED event; mark offline when port closes.
2. ADB orchestrator (every 15s)
adb connectretry; 3 consecutive failures → offline (proxy released after 5 min).- Collect: ro.product.model, ro.build.version.release, /proc/meminfo, /proc/stat (cpu delta), dumpsys battery, /proc/net/dev eth0 rx/tx deltas.
3. Proxy switchboard (every 60s)
- Health: GET https://api.ipify.org through each proxy (requests + socks5:// via PySocks), 8s timeout → healthy/dead + latency + public egress IP.
- Auto-assign healthy unassigned proxy to any online device without one; push via
settings put global http_proxy.
4. Spawn / kill
- POST /api/spawn {count, name_prefix} → background job: free vmid scan (1310+), POST /nodes/pve/qemu/1301/clone {newid, name, full:1}, PUT config {args: unique 59XX display}, POST status/start. 10 max per job, ~4s stagger.
- Kill: qm stop → DELETE VM → release proxy → drop device row.
5. Dashboard + WS
- GET / → static/index.html (Tailwind CDN + Chart.js CDN, dark godhead theme).
- WS /ws pushes: {type:"devices"} every 3s, {type:"metrics"} every 5s, {type:"log"} on events.
REST CONTRACT
| Method | Path | Body/Notes |
|---|---|---|
| GET | /api/status | {devices_online, devices_total, proxies_healthy, proxies_total, uptime} |
| GET/PATCH | /api/devices | PATCH {mac, label} |
| GET/POST | /api/proxies | POST {name, host, port, proto=socks5, user, pass} |
| DELETE | /api/proxies/ | releases assignment |
| POST | /api/proxies//assign | {mac} |
| POST | /api/spawn | {count, name_prefix} → 202 {job_id} |
| GET | /api/spawn/jobs | last 10 jobs |
| POST | /api/device//kill | destroy VM + release proxy |
| POST | /api/device//shell | {cmd} — WHITELIST regex only (getprop, dumpsys, cat /proc, pm list, settings get/list, ls, df, whoami, logcat -d, ip addr, wm size, id, uname) |
| POST | /api/device//screenshot | returns PNG |
| GET | /api/device//screenshot/latest | cached PNG |
| POST | /api/device//reboot | adb reboot |
| GET | /api/logs | last 200 events |
DB SCHEMA (SQLite /opt/android-fleet/fleet.db, WAL)
- devices(mac PK, vmid, ip, model, android, battery, cpu_pct, mem_used_mb, mem_total_mb, adb_state, proxy_name, public_ip, last_seen, first_seen, label)
- proxies(id PK, name, host, port, proto, user, pass, health, latency_ms, assigned_mac, last_check)
- spawn_jobs(id PK, status, count, done, vmid_list JSON, error, created)
HARD LESSONS (baked into this spec)
- system.sfs rebuild: gzip + 128K blocks ONLY (xz hangs boot).
- PVE API status/current may return {"data": null} — never .get() on it blindly.
- requests needs pysocks for socks5:// proxies.
- Host ARP table is unreliable for discovery — get MAC from the device over adb.
- Scan timeout must be >= 1s for emulated NICs.
- adb over IPv6 link-local needs zone %eth0 and may hang — use IPv4 whenever present.
- qm clone full copies ~12GB → free vmid scan must probe existence safely.
- Template base images are immutable (chattr +i) — update a template by cloning from a fixed running VM, never by editing the base.
ACCEPTANCE TESTS
- Spawn 1 → device appears in /api/devices with ip/mac/vmid within 5 min, adb_state online.
- Proxy auto-assigns → device.proxy_name set, public_ip ≠ LAN IP.
- Screenshot endpoint returns a valid PNG.
- Kill → VM destroyed in Proxmox, proxy released, row gone.
- Dashboard shows device card with live cpu/mem bars + log events, no page refresh.