4.2 KiB
12 — Toolchain Setup
First-time setup on a machine (verified baseline: CachyOS/Arch, pacman,
uv present, ADB present, no JDK/SDK/Gradle).
12.1 JDK 17
pacman -S jdk17-openjdk
java -version # expect 17.x
(Compose Multiplatform + current AGP are happy on JDK 17. Use 17 to match the Android toolchain; 21 also works but 17 is the safe floor.)
12.2 Android SDK
# cmdline-tools
mkdir -p ~/android-sdk/cmdline-tools
cd ~/android-sdk/cmdline-tools
curl -O https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip
unzip commandlinetools-linux-*.zip && mv cmdline-tools latest
rm commandlinetools-linux-*.zip
export ANDROID_HOME=$HOME/android-sdk
export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools
sdkmanager --licenses
sdkmanager "platform-tools" "platforms;android-34" "build-tools;34.0.0"
Persist ANDROID_HOME/PATH in ~/.bashrc. ADB is already installed system-wide;
platform-tools from the SDK is fine too (whichever is first on PATH).
Create app/local.properties:
sdk.dir=/home/<you>/android-sdk
12.3 Gradle
No system install — use the project wrapper:
cd app
./gradlew tasks # first run downloads the wrapper distribution
(The wrapper version is pinned in app/gradle/wrapper/gradle-wrapper.properties.)
12.4 hermes environment (for the plugin + running the gateway)
cd hermes-agent
uv sync # creates .venv with all core deps (websockets, httpx, …)
source .venv/bin/activate
hermes --version # sanity
- Run the gateway with the plugin:
# install the plugin (dev: symlink) mkdir -p ~/.hermes/plugins ln -s "$PWD/../gateway-plugin" ~/.hermes/plugins/iris hermes gateway status # should list "iris" hermes gateway # run - Tests use hermes's hermetic runner (never bare
pytest):scripts/run_tests.sh tests/gateway/test_android.py
12.5 Firebase (FCM) — primary push
- Create a Firebase project (console.firebase.google.com).
- Add an Android app (package =
androidAppapplicationId, e.g.dev.iris.app). Downloadgoogle-services.json→app/androidApp/. - Create a service account (Project settings → Service accounts → Generate
new private key) → download the JSON. Store its path in
IRIS_FCM_SERVICE_ACCOUNT(in~/.hermes/.env). - The app's
FirebaseMessagingServiceobtains the FCM token at runtime and registers it viahello/fcm.register.
Skip Firebase → set
IRIS_PUSH_BACKEND=ntfyand configureNTFY_TOPIC/NTFY_SERVER_URL(self-host ntfy or use ntfy.sh). See08-push.md.
12.6 Environment variables (summary)
Secrets (~/.hermes/.env):
IRIS_TOKEN=<64-hex>
IRIS_PUSH_BACKEND=fcm # or ntfy
IRIS_FCM_SERVICE_ACCOUNT=/path/to/service-account.json
# IRIS_FCM_SERVER_KEY=<legacy key> # fallback if no service account
# NTFY_TOPIC=iris-push # when ntfy
# NTFY_SERVER_URL=https://ntfy.sh
# IRIS_WS_CERT=/path/cert.pem # WSS
# IRIS_WS_KEY=/path/key.pem
Behavioral (~/.hermes/config.yaml):
gateway:
platforms:
iris:
enabled: true
extra:
host: 127.0.0.1 # 0.0.0.0 for LAN
port: 8790
home_channel: default
push_backend: fcm
outbox_retention_hours: 72
max_upload_bytes: 104857600 # 100 MB
display:
platforms:
iris:
show_reasoning: true
reasoning_style: code
streaming: true
tool_progress: all # gateway sends full data; app controls display
12.7 Verify the stack (smoke test)
# 1. gateway up with plugin
hermes gateway status | grep -i android
# 2. a raw WS client can pair + echo
python - <<'PY'
import asyncio, json, websockets
async def main():
async with websockets.connect("ws://127.0.0.1:8790/ws") as ws:
await ws.send(json.dumps({"v":1,"type":"hello","payload":{
"token":"<IRIS_TOKEN>","device_id":"test","device_name":"probe",
"caps":{"min_protocol":1}}}))
print("recv:", await ws.recv())
asyncio.run(main())
PY
Expect a hello.ack. If you get error {code:"auth"}, the token/host/port is
wrong.