Running an Autonomous AI Agent Stack on Android with Termux — No Cloud, Just a Phone A developer documented building a fully offline AI agent stack on an old Android phone using Termux, chaining Vosk speech recognition, a quantized llama.cpp model, a JSON command executor, and espeak-ng for spoken feedback. The writeup details Android low-memory-killer kills of the 1.4 GB Llama binary, fixed by dropping to a ~800 MB 3B quantized model, pinning the process with taskset, and capping Node's heap at 256 MB, plus workarounds for Termux heredoc hangs and the lack of a real tmpfs. A Bash watchdog restarts dead processes every 15 seconds and kills the LLM backend when RSS exceeds 800 MB. I’ve spent the last few months trying to turn an old Android phone into a self‑contained AI agent that can listen, reason, and act without ever reaching for a cloud service. The goal was simple: keep the bill at zero, rely only on what fits inside Termux, and learn where the real bottlenecks hide. What follows is a honest walk‑through of the architecture, the things that broke, and the tiny tricks that kept the whole thing alive. Termux gives you a Linux‑like environment without root. You can install packages with pkg , run Node.js, Python, or even compile C binaries. For a phone‑only stack it’s the only realistic way to get a full‑featured shell, a package manager, and persistent storage that survives reboots. The downside? You’re stuck with the phone’s RAM usually 2‑4 GB and no /tmp directory that behaves like a typical Linux tmpfs. Anything you write to /data/data/com.termux/files/usr/tmp is still counted against the app’s private storage, which can fill up quickly if you’re not careful. arecord . llama.cpp . The binary is about 1.4 GB; I store it on the external SD card to avoid eating internal storage. The data flow is: mic → Vosk → text → LLM → JSON command → executor → action → feedback spoken back via espeak-ng . The first time I launched the Llama binary, the phone killed it after ~12 seconds with “Killed”. Android’s low‑memory killer LMK treats any process that exceeds a certain fraction of total RAM as a candidate. With 3 GB RAM, the Llama process plus the Node.js wrapper and Vosk exceeded the limit. Fix: I swapped the model for a 3‑B parameter quantized version ≈800 MB and pinned the Llama process to a specific CPU core using taskset . I also lowered the JVM heap for Node node --max-old-space-size=256 . After those tweaks the LMK left us alone. Termux’s default shell is bash , but it behaves oddly with quoted heredocs when the delimiter contains spaces. I tried to embed a multi‑line prompt for the LLM like this: LLM INPUT=$ cat <<'EOF' You are a helpful agent. Respond with JSON. User said: "$ cat /data/data/com.termux/files/home/last speech.txt " EOF The script would hang waiting for the delimiter because Termux’s bash strips the newline before the closing EOF when the heredoc is quoted. The workaround was to avoid quoting the delimiter and instead escape any $ inside the block: LLM INPUT=$ cat <