DeepSeek Harness Remote
DeepSeek Harness Remote: DeepSeek Harness 실행 PC와 모바일·PC를 안전하게 연결해 어디서나 작업 이어받기
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Android assistant that gets things done on your phone. Describe a task and it taps, types and follows through.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗An Android app that does tasks on your phone for you: say or type what you want, and it uses Claude to look at the screen and tap, type and swipe through your apps until the job is done. It is built first for blind, low-vision and motor-impaired users, and works for anyone who wants hands-free control of any app.
Phones assume you can see the screen and hit small targets. A screen reader tells you what is there, but a five-screen task like "message Sarah that I'm running late" is still dozens of precise gestures. Handy AI turns the sentence into those gestures, can read every step aloud, and stops when you tell it to.
Watch the 60-second demo on YouTube
You need an Android 11+ phone and an Anthropic API key (starts with sk-ant-; Anthropic bills you per use).
The APK on the website can lag behind main. At the time of writing it is 1.5.5 (Claude Opus 4.7); main is 1.5.6 (Claude Opus 5.5). Build from source for the latest.
This is the run in the screenshot above, copied from the app's chat log (v1.5.1 on a Pixel 10). Indented lines are a status row and the tool calls Claude made:
You: take a picture with the phone camera
Screen: 1080x2424
Claude: I'll go to the home screen and open the camera app to take a picture.
key({"action":"home"})
Claude: I can see the Camera app icon. I'll tap it.
tap({"x":336,"y":2035})
Claude: The camera is open in Photo mode. I'll tap the shutter button to take the picture.
tap({"x":540,"y":1810})
Claude: The picture has been taken - I can see the new thumbnail in the bottom-left preview
now showing the image of the office with the chair.
finish({"success":true,"summary":"Opened the Camera app and tapped the shutter button to take a picture. The new photo appears in the thumbnail preview."})
Claude: Opened the Camera app and tapped the shutter button to take a picture. The new photo
appears in the thumbnail preview.
More things to try:
| Say or type | Notes |
|---|---|
| "Message Sarah on WhatsApp that I'm running late." | If voice is on, you get a spoken warning and a pause before it taps Send |
| "Search Google Maps for sushi near me." | |
| "Read me the screen." | Claude calls the on-device OCR tool and the text is read aloud |
| "What did you do?" | Answered on the phone from this chat's log, no API call |
| "What can you do?" | Answered on the phone with example tasks, no API call |
read_screen_text / read_text_at run Google ML Kit OCR on the device.All settings are in the app (gear icon). Nothing is configured with environment variables at runtime.
| Setting | Default | What it does |
|---|---|---|
| Anthropic API key | none | Required. Saved from the key bar or Settings; must start with sk-ant- |
| Voice mode | Auto | Off, On, or Auto (speak only while a screen reader such as TalkBack is on) |
| Narration | Brief | How much of each step is spoken: Off, Brief, Detailed |
| Voice-warn before destructive actions | On | Spoken warning and 1.5 s pause; needs voice to be on |
| Vibration feedback | On | Patterns for started, done, needs attention, error |
| Easy Mode | Off | Single mic button UI |
| Named aliases | none | Added to the prompt so Claude can resolve them |
| High-contrast text | Off | See Limitations |
Agent constants live in code:
| Constant | Value | File |
|---|---|---|
| Model | claude-opus-5-5 | AgentLoop.kt (MODEL, the only place it is set) |
Effort / max_tokens per step | low / 8192 | AnthropicClient.kt, AgentLoop.kt |
| Max steps per task | 40 | AgentLoop.kt |
| Screenshots kept in the conversation | the task's first one plus the 4 most recent; older ones become a text note | AgentLoop.kt |
| Settle delay after each action | 700 ms | AgentLoop.kt |
| Retries | up to 4 attempts on HTTP 408, 429, 500, 502-504, 529 and network errors | AnthropicClient.kt |
Permissions
| Permission | Why |
|---|---|
INTERNET | Calls the Anthropic API |
VIBRATE | Haptic feedback |
| Accessibility service (you turn it on in Android settings) | Take screenshots, perform taps and swipes, set text in the focused field and press Enter, press Back / Home / Recents, show the accessibility shortcut button |
The accessibility service only acts while a task you started is running. It does not process accessibility events (the handler is empty). Its config also declares window-content access, which is used to find the focused text field.
What leaves your phone
| When | What | Sent to |
|---|---|---|
| Every step of a running task | A JPEG screenshot of the whole screen (notifications and anything else visible included), your task text, your named aliases, earlier steps of this task, action results, and any text the OCR tools read | api.anthropic.com, directly from the phone with your key, under Anthropic's API terms |
| Only if you use Set up via computer | Your API key, typed on your computer | Relayed to the phone through the author's server (dashob.com). The setup page says it is held in memory for at most 10 minutes and deleted when the phone collects it |
| Only if you pair in Settings > Cloudbot pairing | A device token, a random device ID and your phone's model name | The author's hub server, over a WebSocket |
Apart from the optional rows above, nothing is sent while no task is running. OCR runs on the device with Google ML Kit, which may send Google usage metrics under its own terms. Crash reporting (Sentry) is compiled in but only starts when a DSN is set at build time; the published APK has none.
What stays on your phone
EncryptedSharedPreferences (AES-256, key in the Android Keystore). If the Keystore is unusable on a device, it falls back to plain app-private storage.Safety. Claude is instructed not to enter passwords or payment details, and not to delete, buy, uninstall or send money unless you asked for that exact thing. That is an instruction to the model, not a sandbox: the service can tap anything you can. Watch what it does and use Stop.
you: "take a picture"
|
MainActivity / EasyModeActivity
| startAgent(key, task)
AgentAccessibilityService ---- TaskRunner (one task at a time, Stop = cancel)
|
AgentLoop, up to 40 steps:
1. takeScreenshot() (Android 11+ accessibility API)
2. POST /v1/messages (AnthropicClient: screenshot + history + tools)
3. Claude replies with a tool call (AgentProtocol parses it, AgentActions validates it)
4. run it: dispatchGesture / ACTION_SET_TEXT / global action / OCR
5. wait 700 ms, take a new screenshot, send it back as the tool result
... until Claude calls finish, Stop is pressed, or the step limit is hit
Tools Claude can call: tap, long_press, swipe, type_text, clear_text, key (back, home, recents, ime_enter), wait (up to 3 s), read_screen_text, read_text_at, finish. Coordinates are screen pixels; the screen size is given in the system prompt.
| Path | Role |
|---|---|
app/src/main/java/com/claudeagent/phone/AgentLoop.kt | The screenshot, Claude, action loop |
AgentProtocol.kt, AgentActions.kt, AgentTools.kt | Response parsing, history trimming, system prompt; tool input validation; tool schemas sent to Claude (pure Kotlin, unit tested) |
AnthropicClient.kt | OkHttp client for the Messages API with retries and immediate cancel |
AgentAccessibilityService.kt, TaskRunner.kt | Screenshots and gestures; runs one agent task at a time |
AccessibilityHelper.kt, ScreenOcr.kt | Text-to-speech, haptics, the destructive-action heuristic; ML Kit OCR |
MainActivity.kt, EasyModeActivity.kt, SettingsActivity.kt, KeySetupActivity.kt | UI |
LocalIntents.kt, NameAliases.kt, ChatStore.kt, ApiKeyStore.kt | On-device answers, aliases, chat history, key storage |
HubClient.kt, HubConnection.kt, HubPairActivity.kt | Optional pairing with the author's agent hub |
OnboardingActivity.kt, SupabaseAuth.kt, AuthStore.kt, EntitlementClient.kt, LemonSqueezyClient.kt, BillingConfig.kt | A trial and subscription mode that is currently switched off (its backend was deleted; see supabase/REBUILD.md) |
PanelClient.kt, PanelPairActivity.kt | Pairing with a retired dashboard; kept only so old pairings can be cleared |
docs/ | The gethandyai.app site, including the APK and the computer key-setup page |
playstore/ | Store listing assets, screenshots and demo videos |
Requirements: JDK 17 and the Android SDK (platform 35). Android Studio provides both.
git clone https://github.com/fainir/handy-ai.git
cd handy-ai
echo "sdk.dir=$HOME/Library/Android/sdk" > local.properties # your SDK path; or export ANDROID_HOME
./gradlew assembleDebug
adb install app/build/outputs/apk/debug/app-debug.apk
The debug build is signed with your local debug key, so uninstall a Play or website copy first (same package name, different signature). No secrets are needed: the optional values in local.properties.example (Supabase, Google sign-in, Sentry) fall back to placeholders and only affect the dormant features.
Release builds read signing details from a git-ignored keystore.properties (storeFile, storePassword, keyAlias, keyPassword), then ./gradlew assembleRelease bundleRelease.
./gradlew testDebugUnitTest # JVM unit tests: no device, no network, no API calls
./gradlew lintDebug
CI (.github/workflows/ci.yml) runs assembleDebug testDebugUnitTest lintDebug on every push and pull request. The unit tests cover response parsing, tool input validation, screenshot-history trimming, the system prompt, local intents, error messages, task cancellation and the hub WebSocket (against a local mock server).
/goal for every turn: sends Claude Code back when it stops early