Skip to content

Releases: Zfinix/asterdroid

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 17 Sep 00:58

Aster Droid 0.2.0

Fewer round trips, shorter waits, and a phone that speaks up on its own.

Experimental. arm64-v8a only. Most of the time a phone task takes is the model thinking between steps, not the phone. This release cuts the number of steps and the time spent waiting between them.


Update

Download asterdroid-0.2.0.apk from the assets below and open it on the phone, or:

adb install -r asterdroid-0.2.0.apk

It installs over 0.1.0 and keeps your settings, keys, sessions and memory. Open the app afterwards and press start if the agent is not running, so it picks up the new instructions.

Fewer model round trips

  • Tap by text. tap Wi-Fi reads the screen as the tap runs and taps the element that says it. An exact match wins over a partial one. If the text is on several elements, the reply lists them and asks for an index instead of guessing.
  • Several steps in one call. do tap Network & internet; tap Internet; tap Wi-Fi runs the steps on the phone, prints one line per step and ends with the final screen. It stops at the first step that errors or changes nothing, and says which steps it did not run. The agent is told to send a known route this way.
  • Shorter receipts. When a screen changes in place, a receipt lists only the rows that changed, and says the rest keep their numbers. A new screen still comes back as the whole map. A tap that changes nothing no longer resends the map.

Waits that fit the phone

  • Learned per app. The service times how long each app takes to react to a touch and to go still, and sizes both waits from that. Apps with little history use the phone's figures. The first few actions after an update use the old fixed waits, so nothing starts out faster than it can back up.
  • A late answer is never lost. A shorter wait can call a slow app's reaction "no change". If the app then changes the screen, the next command is held instead of run, and the reply shows the real screen with held:. This stops a message or a payment from going through twice. The late timing also lengthens that app's wait.
  • pace prints the current waits for the app in front. pace reset forgets them.
  • wait <text> checks again as soon as the screen moves, instead of every half second.

Faster reads on canvas screens

  • capture on starts the screen capture the mirror uses, with nobody watching. ocr, locate, aim and blind taps then take frames from it instead of rate-limited screenshots. It shows the recording indicator, and stops after 30 idle minutes or with capture off.
  • Without a capture, the service learns how far apart the system allows screenshots and waits that long, instead of being refused and retrying.
  • Actions on blind screens wait until the pixels stop changing, instead of a fixed second and a half.

Alerts in the chat

  • Battery. The phone posts to the chat when it runs low, at 20% and 10% by default, once per level per discharge. Ask the agent to change the levels or turn it off (alerts battery 30,15, alerts battery off).
  • Notifications. Ask the agent to forward an app's notifications (alerts add whatsapp) and they arrive in the chat as they come in. Repeated updates of the same notification are sent once. alerts lists what is on.

Alerts are posted as notices, so they do not start an agent turn.

Settings

  • Settings is a full page instead of a sheet.
  • Every key in the agent's .env is shown, including keys for providers other than the current one, which used to look lost.
  • The whole .env can be edited as text, for names no row covers. Saving restarts the agent.

Consent

The agent's instructions are stricter about two kinds of action. Spending money and reaching another person as you (a message, a call, a post) always stop for a yes, with what it is, what it costs and who it reaches. A yes covers the step it was asked about, not the next one. Everything that stays on the phone still just happens.

Known limits

  • The wait timings, text taps and capture frames are new in this release. Report a held: that should not have happened, or a canvas read that got slower after capture on.
  • A screen with a ticking clock or counter can occasionally hold a command after a tap that really did nothing. It costs one extra step.
  • Everything listed under 0.1.0 still applies: text input into views without an input connection, PIN and pattern locks, no start after reboot, arm64-v8a only.

Aster Droid 0.1.0

Choose a tag to compare

@github-actions github-actions released this 15 Sep 08:55

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.