Skip to content

Releases: il90il90/touchless-releases

Touchless v0.2.325

Choose a tag to compare

@il90il90 il90il90 released this 21 Oct 23:06
f77a7c9

Touchless v0.2.325 (code 335)

Issue: #240 (owner, 2026-10-21): every visible feature must work. Nothing should be marked "not available yet".

Learn from screen recordings now works

  • Settings ▸ Learned skills ▸ Learn from screen recordings (user-only opt-in, off by default). When it's on,
    Learn from a recording opens a picker. You choose a screen recording and Touchless analyzes it on the
    phone
    : it detects screen changes and runs ML Kit text recognition on each new screen.
  • Only a redacted text outline is saved. Runs of 4+ digits and secret-looking tokens are masked, and the video
    is never uploaded, copied or kept. Outlines can be viewed and deleted.
  • start_teaching source=recording recording_demo=<id|name> starts Teach Mode and returns the outline. The AI
    performs the flow once and saves it as an ordinary replayable macro, so every confirmation and guard still
    applies. With the opt-in off the answer is DISABLED and nothing is read. With no analyzed recording the
    answer is NEEDS_RECORDING_DEMO, along with the list of available recordings.
  • Limit: the on-device OCR reads Latin script, so Hebrew-only screens produce little text.

Other unfinished features made real

  • run_ui_test → compare_screenshot does a real pixel diff (max_diff_ratio, tolerance) and FAILs when
    the screen differs. Before, it said "not implemented".
  • Cloud voice has a Settings card (endpoint, key, voice, language, plus a Test button that reports whether
    cloud audio actually played). Before, it could only be configured over MCP.
  • Safety & permissions center is reachable from Settings ▸ Security & lock. It existed, but nothing opened it.
  • Notification triggers: older rules still fire, so Settings now shows an entry to review, pause or delete
    them. The entry appears only when such rules exist.

Removed from the UI (owner request)

  • The Fast actions toggle and the Open Quick command button are hidden from Settings. The stored setting
    is unchanged.

Verification: Android CI run 39683079624 passed (unit tests, debug + androidTest build, relay typecheck). Local
pure-Kotlin tests passed: PixelDiff 4, RecordingAnalysis 6, TeachSource 5, HardcodingGuard. Device E2E: NOT TESTED.

Touchless v0.2.324

Choose a tag to compare

@il90il90 il90il90 released this 21 Oct 22:48
f77a7c9

Touchless v0.2.324 (code 334)

Issues: #117 (P0, device-verified root cause) and #217 (owner UX feedback on the AI Providers screen).

#117 — WhatsApp watches never fired on the S23: the contact has several numbers

Owner-authorized two-phone run on v0.2.321 (S23 ↔ Fold): a message from the Fold reached the S23 as a
WhatsApp notification whose sender resolved to an opaque Person key, and all three phone-bound watches
missed with sender_mismatch. The Fold's contact on the S23 has four phone numbers, so the #70
"exactly one number" rule in SenderResolver never resolved it.

  • SenderCandidates (pure, unit-tested): one distinct number resolves as before; several numbers that all
    belong to one contact resolve to the number an ACTIVE watch is bound to; numbers spread over different
    contacts with the same name, or no bound number, stay unresolved ("never match the wrong person on a name").
  • Contact queries carry CONTACT_ID; EventHub.boundActorRefs (Room flow of the active watches' actorRefs)
    feeds the resolver on the notification thread.
  • The reverse direction (S23 → Fold) passed on v0.2.321 for log, reply_exact (reply visible on the other
    phone), notify and queue_for_ai; the Fold → S23 re-run on this build is the acceptance test.

#217 — AI provider setup: one key, nothing else

  • The AI Providers screen paints the theme background (it rendered on a white window with an invisible title)
    and is now vendor + API key + Save. Name, endpoint, model (+ Discover), pricing, pull-only mode and the
    plain-http LAN opt-in moved under Advanced; each vendor has a sensible default model (OpenAI gpt-4o-mini,
    Anthropic claude-3-5-haiku-latest, Gemini gemini-2.0-flash, xAI grok-3-mini); a local/custom server
    takes the first model it lists on Save.
  • Home gets an "AI provider" card under the connection card (which provider answers, ready / not ready).
    Opening it — from Home or Settings — asks for the phone's fingerprint / lock first, the same gate as the
    private MCP link, because the screen holds API keys.

Testing

  • Local pure-Kotlin harness: Event Hub package green (incl. SenderCandidatesTest).
  • Android CI: one dispatch at completion (unit tests + debug/androidTest build + relay typecheck).
  • Device: Fold → S23 WhatsApp re-run after install (reported on #117).

Touchless v0.2.323

Choose a tag to compare

@il90il90 il90il90 released this 21 Oct 22:27
f77a7c9

Touchless v0.2.323 (code 333)

Release issue: #241. Builds on v0.2.322.

Copy MCP URL is now at the top

  • The Copy MCP URL button moved from the "Connect your AI" card to a small pill in the Home header,
    next to the licence pill.
  • Copying asks for your fingerprint, face or phone PIN first (Android's own prompt; change it in
    Settings → Security & lock). The ⋮ menu next to it holds Show as QR and Revoke & regenerate,
    and both ask for the same confirmation. Revoke didn't ask before.
  • The Connect card is gone from Home. Connection status is still shown on the agent card.

"?" — learn Touchless with your AI

  • The ? button no longer opens the static "What Touchless can do" list. It shows the AI apps installed
    on your phone (ChatGPT, Claude, Gemini, Grok, Perplexity, Copilot, DeepSeek, Mistral — only the ones you
    have), plus Other app… and Copy prompt only.
  • Pick one and it opens with a ready prompt. Press Send and you get a complete guide to Touchless in your
    phone's language: every tool, every permission (what it does, what stops working without it, how to grant
    it), every screen, setup steps, automations, privacy, troubleshooting and examples, with icons and tables.
  • The prompt is built from the app itself, so it always matches your version. It never includes your
    private connection link or token. It is also copied to the clipboard in case an app doesn't fill it in.

Testing

  • Android CI (one dispatch): unit tests + debug/androidTest build + relay typecheck.
  • New HelpPromptTest (prompt contents, trimming, never the link/token).
  • Test infrastructure: the diagnostics journal no longer opens its database under Robolectric. That async
    open raced test teardown and crashed unrelated tests.
  • Device check: NOT TESTED yet (owner checks the header pill and the "?" chooser).

Touchless v0.2.322

Choose a tag to compare

@il90il90 il90il90 released this 21 Oct 22:16
f77a7c9

Touchless v0.2.322 (code 332)

Release issue: #238. Builds on v0.2.321.

#238 — Install APKs straight to the phone (upload → install → auto-delete)

Your AI can now send an APK to the phone without hosting it at a link.

  • create_apk_upload (served by the relay) returns a single-use upload link that is valid for one hour.
    The AI uploads the file to it (curl -fT app.apk <upload_url>), or you open the link in any browser and
    pick the APK. The connection token is never put in a URL; the link's random id is the one-time credential.
  • install_uploaded_apk: the phone downloads the file from the relay with its own token, verifies it
    (optional sha256 / package_name), deletes the relay copy, and opens the system installer. You
    still confirm the install.
  • Nothing stays on the server. If the phone's delete doesn't arrive, the relay removes the copy as soon
    as the phone reports the download. Anything not installed is wiped automatically after an hour.
  • Limits: ZIP/APK files only, up to 95 MB, at most 3 open uploads per connection.
  • Works the same on the default Cloudflare relay and on a self-hosted relay (set RELAY_PUBLIC_URL so
    upload links use your public https address). See docs/SELF_HOSTING.md.

Testing

  • Self-hosted relay: npm run test:selfhost, including the new uploads.test.mjs (upload page, auth,
    non-APK rejection, single use, token isolation, download and relay delete, slot cap).
  • Worker run locally with wrangler dev: a 60 MB upload and download matched byte for byte, and a simulated
    phone completed the install, after which the relay copy was deleted.
  • Android unit tests: tool parity, safety, onboarding and the new UploadedApkTest.
  • NOT TESTED: a real APK on a physical device through the production Cloudflare relay.

Touchless v0.2.321

Choose a tag to compare

@il90il90 il90il90 released this 21 Oct 21:35
f77a7c9

Touchless v0.2.321 (code 331)

Release issue: #217 (P0). This is a bundle release closing out the actionable board in one signed
build (owner policy: one regular release per completed delivery, never per commit). Issues covered:
#217, #149/#150 (code half), #104, #133, #110, #105, #27, #145, #35, #50, #151, #29, #174, #111, #114,
#23, #12. Draft PRs #180 and #186 were re-implemented on current main and closed as superseded.

#217 — autonomous AI replies (real provider inference, same conversation, exactly once)

  • One engine, not two. v0.2.320 (released by the parallel session an hour earlier) shipped the same feature as
    generate_with_ai with its own runner. This release keeps that action name as an alias (existing watches and
    their camelCase payloads keep working) and routes both names through the single AutonomousReplyRuntime,
    which carries everything v0.2.320's runner lacked: the ThreadReplyGuard/DraftReplyStore exactly-once send,
    same-conversation transcripts, echo verification and the per-row lifecycle. v0.2.320's pure planner
    (AutonomousReplyPlanner: pull-only → QUEUED, missing key → WAITING_PROVIDER), usage counters
    (ProviderUsageStore) and the Settings → AI Providers screen are kept and wired into that runtime.
  • Keys and endpoints are Settings-only. configure_ai_provider over MCP rejects api_key, base_url and
    trust_lan_http: a remote AI can rename a connection, pick its model or make it the default, but can never
    store a key or redirect where messages are sent.
  • Root cause fixed: only queue_for_ai watches hand an event to the Agent Router; log/notify/
    reply_exact/run_script no longer leak agent_event rows to the AI (owner's live finding #1).
  • New Event Hub action ai_reply: Touchless itself calls a configured provider API (OpenAI-compatible,
    Anthropic Messages, Gemini generateContent) with the incoming message quoted as untrusted data plus the
    owner's instructions, resumes the same per-contact conversation (durable transcript keyed
    connection | package | verified thread; restart-safe, bounded), sends exactly once through the shared
    ThreadReplyGuard/DraftReplyStore (unverified sender / group / self / rate limit → held as a draft,
    never sent), and verifies the outbound send when the app echoes the owner's own message.
  • Honest lifecycle on the delivery row, with correlation ids: PROVIDER_WOKEN → CONVERSATION_RESUMED → AI_REPLIED → UNKNOWN (attempted) → OUTBOUND_VERIFIED, or DRAFTED / AI_DECLINED / FAILED.
    list_event_deliveries returns correlationId, action-aware outcome and confirmedSend.
  • Provider connections: Settings → AI Providers (keys encrypted on-device, never returned) plus the MCP
    tools configure_ai_provider (model / name / default only) / list_ai_providers / test_ai_provider /
    delete_ai_provider. watch_event action_type=ai_reply refuses creation when no connection is ready.
  • Docs: docs/AUTONOMOUS_AI_REPLY.md (chain, states, config, device acceptance matrix).
  • NOT TESTED on device: the two-phone WhatsApp/Telegram run needs a stored provider key (none in CI).

#104 — one persistent notification; #133 B23/B26; #27 config-driven ignore list

  • NotificationPolicy is the single sanctioned poster: accessibility-off, wrong-PIN, recovery and health
    alerts fold into the foreground notification; completion / schedule / morning-summary / AI-finish / Event
    Hub posts go through the policy (userRequested honoured). Obsolete channels cleaned on upgrade.
  • Notification classification: self, group_summary, otp, email, navigation/transport/
    progress, message (MessagingStyle/CATEGORY_MESSAGE only), else notification. A Samsung Clock timer
    is no longer a "message". Pre-upgrade watches naming message keep their old catch-all (legacyMessage,
    Room migration 1→2). read_notifications and route_action notifications_list share one deduped inbox.
  • OTP privacy: codes masked (••••) in stored/delivered payloads, logs, audit, history and the pending
    inbox; per-watch include_code opt-in exposes the live code in memory only.
  • NotificationTrigger ignore list is a setting (notification_trigger_ignored_packages), no hardcoded
    AI-app list; .notify( baseline shrank from 14 keys to 6.

#133 / #110 / #105 — remaining device-QA defects

calendar create/list (writable calendar, instances, dedupe, ids), clipboard honesty (UNREADABLE_BACKGROUND,
verified read-back), max_chars exact, listen_speech hard timeout, exit_split_screen real display +
divider-drag fallback, structured mock-location results, get_ui_tree limits, interact_with_element
value/new_text, window-set verification token (IME/popup changes count), tap_text gesture fallback,
run_ui_test truthful verdicts, battery per-UID parsing, speakerphone route polling, update_contact name
parts, action-aware inbox counts, wake_screen verified + wake/keep_screen_on_actions settings,
ai_task_finished only on an explicit task_finished=true hint or a Task reaching DONE (ai_activity_idle
is the inferred signal).

#145 / #35 — automation backup + builder parity

Backup Export/Import via SAF (Merge / confirmed Replace; imported items paused until reviewed) wired to the
real watch/schedule/task stores; export_automations / import_automations / list_automations MCP tools;
device-side ParamSpec schemas for 20 common tools with a parity test against the relay; read-only
Automation Flow view (trigger → condition → steps) with scalar-parameter edits only.

#50 / #35 / #151 — queue, schedules, AI-active indicator

  • Single owner of screen actions: every tool execution (relay, schedule, Event Hub, scripts, UI) goes
    through ActionOwner at the dispatcher chokepoint; screen-changing tools run one at a time in arrival
    order, reads stay concurrent, cancel/management tools never wait. A 45 s bounded wait returns an honest
    "Device busy with ; retry" instead of a ghost run. get_agent_diagnostics.action_owner exposes it.
  • One durable FIFO on the existing TaskStore (seq/priority/source/scheduledFor), a single
    TaskQueueRunner, and one enqueue path: Event Hub task/workflow watches, scheduled fires and
    execute_workflow async:true all create queued tasks; crash recovery re-queues instead of resuming inline;
    cancel_task cancels only its own task. New manage_task (pause/resume/cancel/prioritize/replace);
    list_tasks reports queue position and owner state; Tasks screen "Queue" section + "Pause queue"; the
    floating panel shows the current task, step n/m, elapsed and the next three.
  • Schedules: per-schedule run history (scheduled vs actual time, outcome), start/end/max-runs bounds
    (schedule_action, manage_scheduled_task update, backup round-trip), pause/resume per card, a guided
    3-step create/edit flow with a live next-3 preview, TV-scaled focusable cards.
  • AI-active indicator: shown only while a tool actually executes on any path, hides immediately when the
    setting is turned off, hidden during captures; ai_active_indicator_enabled is AI-configurable.

#29 / #174 / #111 / #114 / #23 / #12

  • TV: press_key back/home verified against the foreground app, paste / focus_click keys, post-boot
    accessibility repair via Shizuku (once per boot, never over a deliberate OFF).
  • Onboarding: persisted "skip", 24 h "Finish background setup" nudge, localized copy.
  • Safety: one shared CommitGuard (scope, UI-stable, target, recipient/payload binding, duplicate ledger)
    used by learned skills, Teach replay, workflows, run_actions and scripts; Teach replay stops after an
    unverified side effect.
  • Learning: learn_from_recordings_enabled (OFF) and an honest UNSUPPORTED for recording demonstrations;
    docs distinguish recording / Teach macro / learned skill.
  • Self-hosting: LAN profile docs corrected (binds ${RELAY_LAN_IP}), Docker Desktop/WSL2 note, LAN-bind
    regression test.
  • Fast Actions: Unavailable / HandedOff outcomes and a read-only AI fallback through a configured
    provider connection; Quick command entry restored in Settings.

Testing

  • Android CI (android-ci.yml, one dispatch): unit tests + debug/androidTest build + relay typecheck.
  • Local pure-Kotlin harness (no Android SDK reachable from the build container): 900+ unit tests green.
  • Relay: typecheck + 49 self-host tests green.
  • Device E2E: NOT TESTED in this batch (owner-run; see each issue's acceptance matrix).

Touchless v0.2.320

Choose a tag to compare

@il90il90 il90il90 released this 21 Oct 20:33
f77a7c9

Touchless v0.2.319

Choose a tag to compare

@il90il90 il90il90 released this 21 Oct 12:17
f77a7c9

Touchless v0.2.318

Choose a tag to compare

@il90il90 il90il90 released this 21 Oct 05:18
f77a7c9

Touchless v0.2.318 (code 328)

Issue: #112 — truthful rejection of unopenable navigation (continuing the destination-verification work).
Also: #23 — concrete LAN self-hosting troubleshooting docs.

#112 — don't claim success when nothing can open it

  • open_location_on_map and navigate_to now check that a handler actually resolves on the device and
    reject truthfully ("No app on this device handles 'geo:' links" / "…can start navigation") instead of
    launching a geo: / google.navigation: intent into nothing and reporting "opened". When a map/navigation
    app is installed, behaviour is unchanged.
  • Builds on the earlier #112 slice (v0.2.316): launch_app destination verdicts (foreground / wrong_app /
    unverified) and the pure DestinationVerifier / EntryPointRegistry / UriSchemeSupport helpers.

#23 — self-hosting LAN troubleshooting

docs/SELF_HOSTING.md gains concrete rows for the exact "localhost works, the phone on Wi-Fi can't reach it"
failure: starting the LAN compose profile, the Windows Defender inbound rule (Private only), Docker
Desktop/WSL2 port mapping, AP/client isolation, the cleartext opt-in, and why the no-token :8788 bridge stays
localhost-only. (The full Windows + LM Studio end-to-end proof still needs that physical setup.)

Testing

  • PASS (Android CI): compile + unit tests green (the UriSchemeSupport/DestinationVerifier suites included).
  • NOT TESTED: physical-device E2E (owner's QA agent).

Touchless v0.2.317

Choose a tag to compare

@il90il90 il90il90 released this 20 Oct 18:24
f77a7c9

Touchless v0.2.316

Choose a tag to compare

@il90il90 il90il90 released this 20 Oct 17:53
f77a7c9

Touchless v0.2.316 (code 326)

Issue: #112 — verify the actual destination of a navigation, not just that an app launched (first slice).

Honest destination verification for app launches

Launching an app now reports where it actually landed, instead of a vague "launched":

  • foreground — the app really came to the front (VERIFIED).
  • wrong_app — a different app or a chooser intercepted focus (so the AI knows it didn't land where it meant to).
  • unverified — the foreground couldn't be read (e.g. Accessibility unbound); reported honestly, never a fake success.

Built on three pure, unit-tested helpers (reused by the broader navigation work to follow):

  • DestinationVerifier — classifies right-app/right-screen vs wrong-app/wrong-screen vs unreadable, with
    package + sub-package/component matching.
  • EntryPointRegistry — a per-app registry of discovered deep entry points, invalidated when the app changes
    version so a stale entry is never reused.
  • UriSchemeSupport — classifies a URI truthfully (web vs handler-scheme vs unsupported) so an unopenable
    scheme (e.g. geo: with no handler) is rejected with a reason rather than launched into nothing.

Still to come on #112

Dynamic discovery of exported intents/app-links into the registry at runtime, destination verification wired
into open_url/navigate_to, and physical-device E2E. Tracked on the issue.

Testing

  • PASS (Android CI): the three new pure unit suites (destination verdicts, registry staleness, URI classification).
  • NOT TESTED: physical-device E2E (owner's QA agent).