Skip to content

Tentatively Working Termux Build #5

Description

@SlothMecha

Good evening,

I was messing around with the official Hermes agent Termux CLI and was able to successfully get it running despite some initial compiling issues I ran into from building via the Linux instructions. It's been running without major issues for me on my Android 13 phone, and I personally am loving the UI compared to theme readability issues I run into with even modified Termux CLIs. I'm posting this here as a summary of Hermes' work to hopefully provide some insight and future ideas if you want to make any changes to officially support how your project works/installs for Android.

As practically an amateur user, your mileage may vary on how safe and viable any of this is. Run at your own risk!

...
Date: 2026-07-13
Target: hermes_client (https://github.com/lotsoftick/hermes_client) on
Termux (aarch64 / Android 13, SDK 33), Node v26.3.1, npm 11.17.0
...
SUMMARY

hermes_client CAN run on Termux/Android, but the standard npm install +
npm run dev flow fails in three distinct ways due to (a) Termux having no
prebuilt native binaries for its bionic libc, and (b) a Termux-specific quirk
where npm strips node_modules/.bin (and /data/.../usr/bin) from the PATH of
package install/lifecycle scripts. All issues were resolved with workarounds;
no source code changes to hermes_client were required.


PROBLEM 1 — better-sqlite3 and bcrypt have no Termux prebuilt binaries

Symptom:
npm ERR! node-gyp ... better-sqlite3 ... build error
(and, separately, bcrypt fails at runtime: "No native build was found")

Cause:

  • better-sqlite3@12.8.0 ships prebuilt binaries only for standard
    linux-x64 / darwin / win32. On Termux (linux-aarch64-android, bionic libc)
    no matching prebuilt exists, so it must compile from source.
  • bcrypt ships prebuilts for linux-arm / linux-arm64 but ONLY as glibc/musl
    flavors. Android uses bionic libc, so none of the prebuilts load. Worse,
    bcrypt's install script is ONLY node-gyp-build (prebuilt lookup) with NO
    node-gyp rebuild source-compile fallback — unlike better-sqlite3 which
    falls back to node-gyp rebuild --release.

Fix (build both from source):
export GYP_DEFINES="android_ndk_path=''"

better-sqlite3:

cd ~/hermes_client/api/node_modules/better-sqlite3
node /data/data/com.termux/files/usr/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js rebuild --release

bcrypt:

cd ~/hermes_client/api/node_modules/bcrypt
node /data/data/com.termux/files/usr/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js rebuild --release

Notes:

  • The critical env var is GYP_DEFINES="android_ndk_path=''" — without it
    node-gyp's build fails in Termux. This is documented in upstream
    better-sqlite3 issue #857.
  • The native compile on a phone takes ~10 minutes. Be patient.
  • OpenSSL dev headers (needed by bcrypt) are present in the Termux package
    set; ensure pkg install nodejs python make clang binutils is done first.

PROBLEM 2 — npm strips node_modules/.bin from lifecycle-script PATH

Symptom (during npm install):
npm error code 127
npm error path .../api/node_modules/bcrypt
npm error command sh -c node-gyp-build
npm error sh: 1: node-gyp-build: not found
(also appears for better-sqlite3-adjacent steps and for nodemon/vite)

Cause:
On this Termux environment, when npm runs a package's install/lifecycle
script (e.g. sh -c node-gyp-build, sh -c nodemon ..., sh -c vite),
the child shell's PATH does NOT include node_modules/.bin. Even installing
node-gyp-build globally (so it lives at /data/.../usr/bin/node-gyp-build)
does not help, because the script subshell also lacks the Termux bin dir on
its PATH. This causes a chicken-and-egg failure: every npm install aborts
on bcrypt's postinstall before node-gyp-build can be placed in .bin.

Fix that gets past it:

1. Download everything WITHOUT running install scripts (this is what

actually populates node_modules/.bin/node-gyp-build):

cd ~/hermes_client/api
rm -rf node_modules package-lock.json
npm install --ignore-scripts

2. Then run the native compiles directly (see Problem 1). npm rebuild

still fails here because of the same PATH issue, so invoke node-gyp by

ABSOLUTE path instead.


PROBLEM 3 — npm run dev cannot find nodemon / vite

Symptom:
[API] sh: 1: nodemon: not found
[CLIENT] sh: 1: vite: not found
(dev.js spawns npm run dev in api/ and client/, which invoke nodemon and
vite via sh -c; both fail for the same .bin-on-PATH reason as Problem 2.)

Additional wrinkle: the root node_modules/.bin/vite symlink is never created
because only api/ had npm install run (the root install was never done).
vite exists only as node_modules/vite/bin/vite.js at the repo root.

Fix (launch the two servers directly, bypassing npm scripts entirely):
export GYP_DEFINES="android_ndk_path=''"
export API_PORT=18889
export CLIENT_PORT=18888
export PATH="$HOME/hermes_client/api/node_modules/.bin:$HOME/hermes_client/node_modules/.bin:$PATH"

API:

cd ~/hermes_client/api
node ./node_modules/ts-node/dist/bin.js ./src/app.ts

Client (note: invoke vite.js by absolute path — the .bin symlink is absent):

cd ~/hermes_client/client
node ../node_modules/vite/bin/vite.js --host --port 18888

Other Termux gotchas hit along the way:

  • ts-node's bin has a shebang #!/usr/bin/env node; executing the .bin
    script directly fails with "bad interpreter: /usr/bin/env: no such file
    or directory" because Termux's env lives at a different path. Fix: run
    ts-node THROUGH node (node ./node_modules/ts-node/dist/bin.js ...)
    rather than executing the shebang script.
  • nodemon CLI args containing a glob (*.d.ts) are expanded by zsh and fail
    with "no matches found"; avoid shell globbing in the command.

VERIFICATION (what "working" looks like)

  • Client (Vite) serves HTTP 200 on http://localhost:18888
  • API serves HTTP 301 (redirect to /api/docs/) on http://localhost:18889
    (a 404 on / and 301 on /api/docs are both signs the server is up)
  • Native artifacts present:
    api/node_modules/better-sqlite3/build/Release/better_sqlite3.node
    api/node_modules/bcrypt/build/Release/bcrypt_lib.node
  • Default login: admin@admin.com / 123456

SUGGESTIONS FOR MAINTAINERS

  1. Termux/bionic has no prebuilt native binaries for better-sqlite3 or bcrypt.
    Consider documenting the --ignore-scripts + source-build workaround, or
    switching the API datastore to a pure-JS option to avoid native deps on
    Termux entirely.
  2. npm on Termux does not expose node_modules/.bin to lifecycle scripts'
    subshells. A script that launches servers via absolute binary paths (or
    uses npm exec / npx) would be more portable than relying on npm run
    resolving .bin in a child sh.
  3. The root project's npm install does not install workspace deps (vite at
    root, nodemon/ts-node in api/). Running install only in api/ leaves the
    root .bin/vite symlink missing. Either document a full root install or make
    dev.js resilient to missing .bin entries.

================================================================================
This report was produced while getting hermes_client running on a real
Termux/Android device. No source modifications were made; all fixes are
environment/launch workarounds.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions