Understanding the Android/Termux Environment
Android is not a standard Linux environment. Termux provides a Linux-like userland, but with critical differences that break most Node.js applications designed for desktop Linux.Key Differences
- No
/tmpdirectory - Termux uses$PREFIX/tmpinstead - No systemd - Uses runit for service management
- Restricted paths - Apps can’t write to standard Linux paths
- Aggressive process killing - Android kills background processes without wake locks
- Non-standard build environment - No Android NDK by default
Critical Environment Variables
TMPDIR / TMP / TEMP Issues
Problem: OpenClaw and many Node.js dependencies expect to write temporary files to/tmp/. This path:
- Doesn’t exist in Termux
- Can’t be created (permission denied)
- Even if created, isn’t writable by Termux apps
/data/data/com.termux/files/. The standard /tmp is either:
- Non-existent
- Part of Android’s root filesystem (not accessible)
- Used by Android system (not writable by Termux)
setup_claw.sh:25-47
$PREFIXexpands to/data/data/com.termux/files/usr/$PREFIX/tmpis writable by Termux- Setting
TMPDIR,TMP, andTEMPcovers all common temp directory conventions - Exporting immediately + adding to
.bashrcensures it works now and persists
The script cleans old entries with
sed -i '/export TMPDIR=/d' to prevent duplicates if re-run.PATH Configuration
Problem: When running as a service (via runit), the process doesn’t inherit your shell’s PATH. The service can’t findnode, npm, or openclaw commands.
Error Messages:
setup_claw.sh:81-89
- Services run in a minimal environment without shell initialization
- Explicitly setting
PATH=$PREFIX/binensures Node.js and npm binaries are found TMPDIRis also set here as a failsafe
Hardcoded /tmp/openclaw Path
Problem: This is the most critical issue. OpenClaw’s source code contains hardcoded references to/tmp/openclaw:
/tmp is universally available. The developers didn’t anticipate Android/Termux deployment.
The Fix:
The setup script patches the compiled code after installation:
setup_claw.sh:60-70
- Uses
sedto find/replace all instances of/tmp/openclawwith$PREFIX/tmp/openclaw - Operates directly on the installed JavaScript file
- Must be re-applied after every update (hence the update script)
TMPDIR environment variable. However:
- We don’t control the upstream source
- Build process may take time
- This workaround is reliable and simple
Node-GYP and Android NDK
The Problem
Error Messages:- A C++ compiler (clang/gcc)
- Python (for build scripts)
- Make/CMake (build tools)
- On Android: Android NDK (Native Development Kit)
- Non-standard paths
- Looking for Android NDK (which isn’t needed for Termux)
- Build environment detection failures
The Workaround
Step 1: Install build toolssetup_claw.sh:21-23
setup_claw.sh:49-53
- Node-GYP reads
~/.gyp/include.gypifor build configuration - Setting
android_ndk_pathto empty string tells it “NDK not available, use standard toolchain” - This prevents NDK detection errors while allowing native compilation
- Termux’s clang is sufficient for building native Node modules
This is a workaround, not a proper fix. It prevents Node-GYP from searching for NDK while still allowing native module compilation using Termux’s toolchain.
Service Management (Runit vs Systemd)
Why No Systemd?
Android doesn’t use systemd. It has its own init system (Android Init), which is:- Not accessible to user-space apps like Termux
- Completely different from Linux init systems
- Requires root access to modify
Termux-Services (Runit)
Termux providestermux-services package, which uses runit - a lightweight service supervisor.
Key Concepts:
- SVDIR - Service directory (
$PREFIX/var/service) - supervise - Runit’s process supervisor
- sv - Service control command
- service-daemon - Termux wrapper that starts runit
setup_claw.sh:72-106
setup_claw.sh:103-110
- Sets
SVDIRsosvcommand knows where services are - Restarts service-daemon to ensure runit is supervising
- Makes it persistent via
.bashrc
Race Condition Handling
setup_claw.sh:112-116
supervise directory. This loop waits up to 5 seconds for supervise/ok to exist before running sv-enable.
F-Droid vs Google Play Termux
Use F-Droid Termux
Correct source: https://f-droid.org/packages/com.termux/ Differences:| Aspect | F-Droid Termux | Google Play Termux |
|---|---|---|
| Updates | Active | Frozen (2020) |
| Package compatibility | Modern | Outdated |
| Node.js version | Latest LTS | Old versions |
| termux-services | Works | May fail |
| Build tools | Full support | Limited |
- Backup your data (if needed)
- Uninstall Google Play Termux
- Install F-Droid app from https://f-droid.org/
- Install Termux from F-Droid
- Run setup script again
You cannot simply update from Google Play to F-Droid. They use different signing keys, so you must uninstall first.
Storage and Permissions
Storage Access
Termux needs permission to access shared storage for certain operations. Grant storage permission:~/storage/ with symlinks to:
~/storage/downloads- Android Downloads folder~/storage/dcim- Camera photos~/storage/shared- Internal storage root
Wake Lock (Critical for Background Operation)
Problem: Android kills background processes to save battery. Without wake lock, the service stops when:- Screen turns off
- Termux app is closed
- After a few minutes of inactivity
~/.bashrc so it’s enabled on every shell start:
Battery Optimization
Even with wake lock, Android may still kill Termux due to battery optimization. Disable battery optimization:- Go to Android Settings
- Apps → Termux
- Battery → Unrestricted (or “Don’t optimize” on older Android)
Summary of Fixes
The setup script addresses these environment issues:| Issue | Fix | Location |
|---|---|---|
No /tmp directory | Set TMPDIR=$PREFIX/tmp | Lines 25-47 |
Hardcoded /tmp/openclaw | Patch entry.js with sed | Lines 60-70 |
| Node-GYP NDK errors | Create dummy ~/.gyp/include.gypi | Lines 49-53 |
| Service can’t find node | Explicitly set PATH in run script | Lines 81-89 |
| Service stops randomly | Manual wake lock + battery optimization | User action |
| No systemd | Use runit via termux-services | Lines 72-118 |
| Updates overwrite patch | Re-apply patch in update script | update_claw.sh |