readme rewritten with ascii diagrams, detailed setup, and conversational tone.
root package.json updated with packageManager field for bun, web workspace,
and build/start scripts pointing to web/ for railway railpack compatibility.
- Make screen capture permission and battery optimization states reactive
- Add lifecycle observer to refresh battery status on resume
- Add lifecycle-runtime-compose dependency for non-deprecated LocalLifecycleOwner
- Replace deprecated LocalLifecycleOwner import
- Remove unused REQUEST_CODE constant
- Use KTX createBitmap() and bitmap[x,y] extensions
- Add misc.xml and junie.xml to .gitignore
Skills (copy_visible_text, find_and_tap, submit_message, read_screen,
wait_for_content, compose_email) were CLI-only using direct ADB. The
server prompt advertised them but they silently failed when chosen.
Now intercepted in the agent loop before actionToCommand() and executed
server-side using existing WebSocket primitives (get_screen, tap, swipe,
clipboard_set). Each skill replaces 3-8 LLM calls with deterministic
server-side logic.
The UI agent had no memory of previous actions — each step was a fresh
single-shot LLM call. After typing and sending a message, the LLM saw
an empty text field and retyped the message in a loop.
- Add RECENT_ACTIONS (last 5 actions with text/result) to user prompt
- Add chat app completion detection rule to dynamic prompt
- Add send-success hints for WhatsApp and Messages apps
- Add git convention to CLAUDE.md (no co-author lines)
- Add empty goal guard in parser (returns done instead of passthrough)
- Replace `as any` casts in pipeline.ts with proper ActionDecision types
- Add runtime type guards for untrusted LLM output in classifier
- Add intent action to dynamic prompt so UI agent can fire intents
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace preprocessor+runAgentLoop with runPipeline in both device.ts
(WebSocket) and goals.ts (REST). The pipeline orchestrates: deterministic
parser (stage 1) -> LLM classifier (stage 2) -> lean UI agent (stage 3).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When pipelineMode is enabled in AgentLoopOptions, the loop uses
buildDynamicPrompt() with per-screen context (editable fields,
scrollable elements, app hints, stuck state) instead of the static
mega-prompt. Legacy mode (default) is unchanged.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Android: fetch installed apps via PackageManager, send to server on connect
- Android: add QUERY_ALL_PACKAGES permission for full app visibility
- Android: fix duplicate Intent import, increase accessibility retry window
- Android: default server URL to ws:// instead of wss://
- Server: store installed apps in device metadata JSONB
- Server: inject installed apps context into LLM prompt
- Server: preprocessor resolves app names from device's actual installed apps
- Server: add POST /goals/stop endpoint with AbortController cancellation
- Server: rewrite session middleware to direct DB token lookup
- Server: goals route fetches user's saved LLM config from DB
- Web: show installed apps in device detail Overview tab with search
- Web: add Stop button for running goals
- Web: replace API routes with remote commands (submitGoal, stopGoal)
- Web: add error display for goal submission failures
- Shared: add InstalledApp type and apps message to protocol
- Add device/session/step DB persistence in server agent loop
- Add goal preprocessor for compound goals (e.g., "open YouTube and search X")
- Add step-level logging to agent loop
- Fix dashboard WebSocket auth (direct DB token lookup instead of auth.api)
- Fix web layout to use locals.session.token instead of cookie
- Add dashboard-ws.svelte.ts WebSocket store with auto-reconnect
- Rewrite devices page with direct DB queries and real-time updates
- Add device detail page with live step display and session history
- Add Android companion app resources, themes, and screen capture consent
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add deleteKeySchema for proper FormData validation
- Return { deleted: true } from deleteKey for change tracking
- Use $state for keysPromise to refresh list after create/delete
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>