Running a 10-tier SQLite agent mesh on Termux without thermal throttling

xhallbeep1 pts0 comments

ApexYX-Sovereign/docs/termux-tutorial.md at main · xhall-beep/ApexYX-Sovereign · GitHub

//blob/show" data-turbo-transient="true" />

Skip to content

Search/

Sign in<br>Sign upAppearance settings

You signed in with another tab or window. Reload to refresh your session.<br>You signed out in another tab or window. Reload to refresh your session.<br>You switched accounts on another tab or window. Reload to refresh your session.

Dismiss alert

{{ message }}

xhall-beep

ApexYX-Sovereign

Public

Notifications<br>You must be signed in to change notification settings

Fork

Star

FilesExpand file tree

main

/termux-tutorial.md

Copy path

Blame<br>More file actions

Blame<br>More file actions

Latest commit

History<br>History<br>History

151 lines (115 loc) · 7.17 KB

main

/termux-tutorial.md

Copy path

Top

File metadata and controls<br>Preview

Code

Blame

151 lines (115 loc) · 7.17 KB

Raw<br>Copy raw file<br>Download raw file

OutlineEdit and raw actions

Running a 10-tier SQLite Agent Mesh on Termux without Thermal Throttling

Phones are hostile hardware for agent systems. A passively-cooled SoC starts<br>throttling within minutes of sustained load, Android kills background<br>processes on a whim, and every polling loop you leave running converts<br>battery into heat into slower clocks into longer loops — a feedback spiral<br>that ends with a warm brick.

This is a walkthrough of the engineering decisions that let a 10-tier agent<br>mesh (message bus, router, executor, scheduler, learner, egress, state, plan,<br>guard, mirror) run indefinitely on a stock Pixel under Termux, with no root,<br>no cloud, and no cooling problems. Case study: ApexYX-Sovereign, which ships<br>these tiers with 421 hermetic self-tests. Everything below is in the shipped<br>code, not aspiration.

1. The enemy list

Three things kill long-running agents on Android:

Thermal throttling. Sustained CPU on a passively-cooled SoC raises<br>die temperature until the kernel governor cuts clocks. Work takes longer,<br>which holds temperature up, which keeps clocks down.

The phantom process killer. Since Android 12, apps (including Termux)<br>get a budget of 32 phantom child processes; exceed it or trip excessive-CPU<br>detection and the kernel starts SIGKILLing your daemons silently.

Doze and app standby. Long sleeps in a background process are not<br>guaranteed to wake on time; timers drift, sockets die.

The common thread: you cannot afford long-lived busy processes. Any<br>architecture built on "N daemons, each polling every few seconds" loses on<br>all three fronts at once.

2. Architecture: ticks, not daemons

Every tier in the mesh is a standalone CLI, and every recurring behaviour is<br>driven by ticks — a single short-lived process that evaluates everything<br>due, does the work, and exits:

mesh_sched.py --tick # evaluate all schedules/triggers once, cron-safe

The scheduler tier stores jobs in SQLite (every 30m, daily 07:30,<br>@boot, five-field cron specs, and sensor triggers like battery:).<br>The tick computes what is due, posts work items onto the bus, and exits in<br>well under a second. Between ticks, nothing is running. CPU duty cycle for<br>the orchestration layer is effectively the tick frequency times tick cost —<br>tens of milliseconds per minute.

Daemon mode exists for the executor (--interval 10) when you want low<br>latency, but it is optional. The design rule: daemons are an optimization,<br>ticks are the contract. A phantom-process kill of a daemon loses nothing,<br>because the next tick reconstructs all state from SQLite.

3. SQLite as the message bus (and why WAL matters on a phone)

The bus is one SQLite file (~/.mesh/bus.db), one table, and a CLI:

mesh post --node me --kind inbox --text "..." # append<br>mesh task --node me --text "..." --for exec # addressed work item<br>mesh claim --id 7 --node exec # exactly-once handoff<br>mesh done --id 7 --node exec # close out

Two pragmas do the heavy lifting:

PRAGMA journal_mode=WAL<br>PRAGMA busy_timeout=10000

WAL lets ten uncoordinated short-lived processes hammer the same file from<br>cron without readers blocking the writer; busy_timeout turns lock<br>collisions into brief waits instead of errors. On flash storage this also<br>concentrates writes into the WAL file instead of scattering page rewrites —<br>kinder to both latency and flash wear.

Rows are append-only and sealed with a sha256 hash chain; mesh verify<br>recomputes the chain and screams if any byte of history was edited. Exactly-<br>once execution is a single UPDATE ... WHERE state='new' compare-and-swap —<br>no distributed-lock machinery, because SQLite is the lock.

4. Thermal admission control: nothing runs unless the phone can afford it

The guard tier is the part most agent frameworks are missing. Before any<br>expensive work runs, it must pass admission:

guard check model --node brain --tokens 4000<br># exit 0 = allow, 10 = defer, 20 = deny — shell-scriptable

The sensor layer reads battery percentage, charging state, and temperature<br>via termux-battery-status when present, falling back to<br>/sys/class/power_supply/battery/* and a...

mesh file termux sqlite tier running

Related Articles