Skip to content

Aster Droid 0.1.0

Choose a tag to compare

@github-actions github-actions released this 15 Sep 08:55
· 11 commits to main since this release

Aster Droid 0.1.0

Aster runs on an Android phone. The full agent, on the device, driven from Telegram.

Experimental. arm64-v8a only. The fast path is four steps and no compiler: install the APK, create a bot, paste two values, send a message. Everything else here is detail.


1. Install the APK

Download asterdroid-0.1.0.apk from the assets below (or the Releases page) and open it on an Android 8+ phone. Android asks once to allow installs from your browser; allow it.

Open asterdroid and grant what it asks for: accessibility, notification access, Do Not Disturb. The agent needs the accessibility service to read and control the screen, so confirm it is on.

Prefer adb? Connect the phone and run:

adb install -r asterdroid-0.1.0.apk

Building from source instead is covered in the appendix.

2. Connect your bot

The phone runs aster remote telegram as a child of the foreground service. That bridge is the whole interface: you never touch the phone, you message it.

  1. Create a bot with @BotFather: send /newbot, follow the prompts, copy the token.
  2. Get an API key from any provider. Groq has a free tier; a local server needs no key at all.
  3. In asterdroid, tap the settings icon in the top right. Paste the token into Telegram token, pick the provider, paste its key. Save. Saving writes the agent's .env and restarts the agent.
  4. Press start and wait for the notification to say Connected to Telegram.
  5. Send hello to your own bot in Telegram, not to BotFather. With no allowed users configured it replies with your numeric user id.
  6. Paste that id into Allowed ids and save. The bot now ignores every account outside the list.

Then send a real instruction:

Open settings and turn on Do Not Disturb.

The agent reads the screen, performs the action and replies with the result.

From your computer instead. Push a .env rather than typing in the settings sheet:

cat > .env <<'EOF'
ASTER_TELEGRAM_TOKEN=YOUR_BOT_TOKEN
<PROVIDER>_API_KEY=YOUR_PROVIDER_KEY
ASTER_REMOTE_USERS=YOUR_TELEGRAM_USER_ID
EOF
adb push .env /sdcard/Android/data/dev.aster.probe/files/.env

The external files dir is the one place adb can write without run-as. Install.env moves the file inside and deletes the outside copy. Pushed values merge with what the phone already has; keys absent from the pushed file survive. If you do not know your user id yet, steps 4 and 5 above get it.

3. Providers, models, keys

The provider catalog is the same providers.json the CLI and desktop read, synced from the Aster repo at build time. The settings sheet lists it, and model lists come from the selected provider's /models endpoint, so the phone offers what the terminal offers.

Pick provider, model and effort in the app's pickers, or in chat with /model and /effort. Either way the agent restarts to apply it.

Keys are plain environment variables named in the catalog's key_env field for whichever provider you selected. The README's Providers table links every provider's key page. Fast picks:

A local OpenAI-compatible endpoint also works, with no key: point ASTER_BASE_URL at Ollama, LM Studio, vLLM or a llama.cpp server.

4. Modes and commands

The agent starts in yolo mode because a phone has no terminal for approval prompts. It announces outbound actions rather than gating them. Change it per chat with /mode.

/help lists the chat commands: /new, /stop, /retry, /queue, /mirror, /mode, /model, /effort, /status, /sessions, /resume, /memory, /remember, /skills, /learn, /checkins, /cron. /mirror returns a browser URL that shows the phone and accepts input.

5. Push to production

release.sh builds a signed release into dist/. It rebuilds both native binaries, runs the Gradle release task, verifies the signature with apksigner and prints a sha256.

./release.sh apk                  # signed release APK
./release.sh aab                  # signed release App Bundle
./release.sh apk -v 0.2.0 -c 2    # set the version, then build
./release.sh apk -s -i            # reuse jniLibs, install over adb

Signing reads keystore.properties and the key it names, both outside git. ./release.sh check reports the SDK, NDK, build-tools, Aster checkout and signing setup without building anything. Install the artifact the same way as the debug build:

adb install -r dist/asterdroid-<version>.apk

From CI

.github/workflows/release.yml runs the same release.sh on GitHub's runners. It checks out Aster beside this repository, installs the NDK, platform 35 and build-tools, cross-compiles both native binaries, then builds and uploads the signed artifacts. A tag push publishes a GitHub Release, using docs/release-notes/vX.Y.Z.md as the body when that file exists.

git tag v0.1.0
git push origin v0.1.0

Set these repository secrets first:

secret what it is
ANDROID_KEYSTORE_BASE64 base64 -i aster-release.jks
ANDROID_KEYSTORE_PASSWORD storePassword
ANDROID_KEY_ALIAS keyAlias
ANDROID_KEY_PASSWORD keyPassword

The keystore is written on the runner and removed with it, so the key never leaves the secrets store. The native build is cached on target/android-tls and target/android-client, which is what keeps a run under the timeout after the first one.

What shipped

  • The agent, not a client. build-agent.sh cross-compiles aster-cli for aarch64-linux-android and packages it as libaster.so. The process on the phone has the same tools, skills, prompts and review path as the terminal version. Sessions, memory and skills live on the device.
  • Hands and eyes. An accessibility service reads and drives the screen: numbered element maps, swipes, drags, pinches, held touches, typing through ACTION_SET_TEXT or a windowless IME, with OCR, screenshot grids and colour-region targeting where the tree is blind.
  • Receipts. Every action returns a dispatch receipt and the observed screen change. An empty diff returns warning: nothing on screen changed; treat as not done.
  • Screen mirror. /mirror returns a browser URL that shows the phone and accepts input. MediaProjection feeds a hardware encoder directly; the wire format follows scrcpy and the Rust server converts to AVCC for WebCodecs.

Known limits

  • arm64-v8a only.
  • Broad permissions: accessibility, notification access, Do Not Disturb, battery exemption.
  • Starts in yolo mode, since a phone has no terminal for approval prompts. Change it per chat with /mode.
  • type cannot reach a view that handles input without opening an input connection, such as some terminals. Read the field back to verify.
  • A reboot means opening the app once before the agent is reachable again; boot start is declared but not wired yet.

Appendix: build from source

What you need

  • An Android 8+ phone or emulator (minSdk 26) connected through adb.
  • An Aster checkout beside this repository, or ASTER_REPO pointing to one.
  • ANDROID_HOME with build-tools and platform 35, an NDK, and kotlinc.
  • A Rust toolchain that can build std for a custom target, with rust-src installed (rustup component add rust-src).

Build and install

./build-agent.sh     # the agent, into app/src/main/jniLibs/arm64-v8a/libaster.so
./build-client.sh    # asterctl and the mirror, as libclient.so
./gradlew assembleDebug
adb install -r app/build/outputs/apk/debug/app-debug.apk
./grant.sh

The first build is the slow one: it builds std from source and a static libffi for the embedded Python. Both land in jniLibs because nativeLibraryDir is the one place Android executes from.

grant.sh grants runtime permissions, app-op access, notification access, Do Not Disturb access and battery exemptions, enables the accessibility service and selects the keyboard, then reports any denied grants. Check that the accessibility service is on. The agent needs it to read and control the screen.