# 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=5555` in 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 single `system.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 unit `android-fleet.service`, WorkingDirectory /opt/android-fleet. SSH key from CT704 → Proxmox authorized_keys (for `ip neigh` ARP). - 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 via `adb 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:5555` then `adb 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 `net0` configs of qemu VMs. - Register new MAC → DEVICE_JOINED event; mark offline when port closes. ### 2. ADB orchestrator (every 15s) - `adb connect` retry; 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) 1. system.sfs rebuild: gzip + 128K blocks ONLY (xz hangs boot). 2. PVE API status/current may return {"data": null} — never .get() on it blindly. 3. requests needs pysocks for socks5:// proxies. 4. Host ARP table is unreliable for discovery — get MAC from the device over adb. 5. Scan timeout must be >= 1s for emulated NICs. 6. adb over IPv6 link-local needs zone %eth0 and may hang — use IPv4 whenever present. 7. qm clone full copies ~12GB → free vmid scan must probe existence safely. 8. Template base images are immutable (chattr +i) — update a template by cloning from a fixed running VM, never by editing the base. ## ACCEPTANCE TESTS 1. Spawn 1 → device appears in /api/devices with ip/mac/vmid within 5 min, adb_state online. 2. Proxy auto-assigns → device.proxy_name set, public_ip ≠ LAN IP. 3. Screenshot endpoint returns a valid PNG. 4. Kill → VM destroyed in Proxmox, proxy released, row gone. 5. Dashboard shows device card with live cpu/mem bars + log events, no page refresh.