npx ghosthand list npx ghosthand screenshot -o home.png # 414x896 on an iPhone XR: screen points npx ghosthand tap 207 448 # same coordinates as the screenshot npx ghosthand scroll down 5 # mouse wheel, ~100 points per tick npx ghosthand tap --text "Settings" # OCR finds the text, taps its center npx ghosthand type "hello" --enter secret-provider | npx ghosthand type --stdin # secrets stay out of argv npx ghosthand key home # Home Screen, not Back npx ghosthand tap 207 448 --screenshot s.png --screentext npx ghosthand screentext --language it-IT
list needs a lease, so two agents never use the same iPhone at once. ghosthand acquire --reason "<task>" prints an id like 42; pass -l 42 to every command and run ghosthand release -l 42 at the end. The examples in this README leave out -l to stay short. See Leases.agent / CLI / curl Mac iPhone │ ┌───────────────────────┐ USB screen capture │ HTTP (unix socket) │ │<─────────────────── screen frames └────────────────────>│ ghosthand daemon │ │ OCR · leases · state │ Bluetooth Classic HID │ │──────────────────> AssistiveTouch └───────────────────────┘ mouse + keyboard pointer, keys
listnpx ghosthand list # run without installing bunx ghosthand list # same, with Bun npm install -g ghosthand # install the `ghosthand` command
ghosthand list
unlock needs the passcode. Keep Low Power Mode off: it forces Auto-Lock to 30 seconds.ghosthand key home
ghosthand assistivetouch # on / off ghosthand assistivetouch off # give the phone back to a person; next tap turns it on
com.apple.Accessibility / AssistiveTouchEnabledByiTunes, about 35 ms (a write is about 40 ms).ghosthand key home # Home Screen (HID consumer Menu key; tested on iOS 15.8)
npx -y skills add https://ghosthand.dev
ghosthand --help first; the help text is the full agent manual.Use ghosthand to open Messages on my iPhone and reply "on my way" to Anna.
ghosthand screentext ghosthand tap --text "Anna" --screenshot s.png --screentext ghosthand type "on my way" --enter --screentext
--screenshot saves it, --screentext prints its text. One call per step instead of three.┌─────────────────────────────────────────────────────────────────┐ v │ 1. see the screen screentext (text + boxes, no image) │ or screenshot -o s.png (~500 tokens) │ 2. act, and see the result tap / swipe / key / type │ + --screenshot s.png --screentext │ 3. read the printed text, and s.png if the text is not enough │ 4. decide the next action toward the user's task ─────────────────────┘
export GHOSTHAND_LANGUAGE=it-IT # phone language for OCR, same as --language ghosthand list ghosthand screentext ghosthand tap --text "Tommaso De Rossi" --screenshot s.png --screentext ghosthand tap 200 610 --screenshot s.png --screentext # x,y read from s.png ghosthand type "ciao" --enter --screentext
GHOSTHAND_LANGUAGE=it-IT (a BCP 47 tag) applies to screentext, --screentext and tap --text. --language overrides it. English is always included. Without it, accents and local words are misread.--screentext output is cheap and often enough to decide (a new title, a sent message). Read s.png for icons, layout, or text OCR misses.type sends keys to the field that has focus, and you cannot see which one from the command. Read a screenshot first: the cursor must be in the field you want. In Messages, Enter in the To: field adds the recipient but keeps focus there, so type "ciao" --enter put "ciao" into To: (tested on iOS 18.7). Tap the message field, check the screenshot, then type.ghosthand type "3336052139" --enter # To: field, adds the recipient ghosthand tap 200 562 --screenshot s.png # check focus in the image ghosthand type "ciao" --enter --screentext # Enter sends
tap --text "..." saves a screenshot read and coordinate guessing. On the Home Screen, app labels do not open apps (tested on iOS 15): tap the icon, about 40 points above the label.screenshot and screentext reject a locked iPhone quickly. If list reports unlocked but capture still gets no frame, see USB screen capture stops.tap 207 100). Check for it first when a screen looks wrong. A stale screen can also come from a secure field: tap outside it and read again.ghosthand tap 207 100 --screenshot s.png --screentext # empty top area: full screen returns
screentext shows no dialog. Take a screenshot, read the image, and tap by position. Enter, Esc, Space, Tab and a center tap did not dismiss the location prompt: a person had to tap Don't Allow. Apple documents Tab and Space for Full Keyboard Access, but that setting is off by default.ghosthand lock at the end of a task. Locking stops USB screen capture and makes the next action less reliable. Use unlock only when list shows [locked].| Command | Does |
list | iPhones on USB, [locked], their Bluetooth link state, and who leases them |
acquire --reason task [--force] [--idle-timeout s] [--label text] | take the iPhone for a task; prints the lease id |
wait --reason task [--timeout s] | wait until another lease ends, then acquire; prints the lease id |
release | end the lease |
screenshot [-o file.png|.jpg] [--settle] | save the screen; --settle waits until it stops changing |
screentext [--language it-IT] [--json] | OCR of the screen: x,y wxh text per line. English is always included |
tap <x> <y> | tap at screenshot coordinates |
tap --text <text> [--index n] | tap the center of an OCR text line (exact line wins, else contains) |
swipe <x1> <y1> <x2> <y2> [--duration ms] | drag with the button held (on a list row it taps the row) |
scroll <up|down> <ticks> [--at x,y] | mouse wheel scroll, ~100 points per tick; scrolls lists that swipe cannot. See docs/scroll.md |
key <combo> | home, enter, esc, backspace, arrows, pageup, pagedown, end, volumeup |
mute / unmute | silence all iPhone sound, or turn it back on; confirmed from the iPhone log |
type <text> | type --stdin [--enter] | validated US-ASCII text; stdin keeps secrets out of arguments |
unlock --stdin | wake and unlock (or GHOSTHAND_PASSCODE); no screenshot while locked |
assistivetouch [on|off] | show or set AssistiveTouch over USB; pointer input turns it on by itself |
lock | lock over Bluetooth with Control-Command-Q |
rename <name> | set the iPhone's name over USB; the id does not change |
forget | remove the Mac's Bluetooth bond with the iPhone, to pair again |
daemon start|stop|restart|status|run | manage the background daemon |
secret-provider | ghosthand type --stdin
--keep-final-newline preserves LF; --enter adds one more Enter. Unsupported controls, invalid UTF-8 and non-ASCII fail before input.mute sets a state; it does not toggle. It is safe to run twice.ghosthand mute # muted iPhone XR Tommy ghosthand unmute
0xE2) toggles iOS full mute: all output, media in every app too. The ringer switch does not silence app media. iOS has no mute state readable over USB lockdown, so the daemon reads SpringBoard's log line after each press:Mac ──BT Mute key──> SpringBoard ──FullMute──> audiomxd ^ │ └──USB syslog_relay─────┘ "Updated fullyMuted to true"
mute-unconfirmed and no second press. Tested on an XR, iOS 18.7. Full mute stays on when screen capture starts or stops.tap, swipe, scroll, key, type and wake accept an expected case-insensitive text substring:ghosthand tap --text "General" --wait-text "About" --timeout-ms 5000
| Variable | Same as | Example |
GHOSTHAND_LANGUAGE | --language (OCR in screentext, --screentext, tap --text) | it-IT |
GHOSTHAND_SCALE | --scale (image and coordinate size) | 1 for native pixels |
GHOSTHAND_PASSCODE | passcode for unlock | user-confirmed secret; prefer unlock --stdin |
GHOSTHAND_LEASE | -l, --lease (every device command) | supported, but agents must pass -l 42 explicitly |
list needs none.ghosthand acquire -d 7EF219AD-69B4-423E-B8C4-4F4A6140822F --label ses_123 --reason "reply to Anna" # prints 42 ghosthand tap -l 42 207 448 # runs on the lease's iPhone; no -d ghosthand release -l 42
agent A: acquire ──> lease 42 ──> tap -l 42, type -l 42 ────────> release -l 42 agent B: acquire ──> error: in use by "ses_123" for "reply to Anna": acquired 2m3s ago, last command 4s ago, ends after 9m56s idle agent B: decides: give up / tell the user, or wait --reason "..." --timeout 600 ─────── waits ──────> lease 43
--reason with the task. A busy acquire fails at once and shows the label, its reason, when it was acquired and its last command, so the next agent can decide to give up instead of waiting.wait is a separate command on purpose: an agent must read who holds the phone before it waits. It retries every second (no queue order). On timeout it shows the current label and reason.--idle-timeout), so a crashed agent never blocks the phone.--force takes it from a lease whose holder is gone; that holder's next command fails with lease-invalid.wait or --force, take a screenshot first. Someone else used the phone.-l. Tool-call environments may not persist; do not rely on exporting GHOSTHAND_LEASE.state.db.--label is only display text, e.g. your agent session id, so others can find who holds the phone. It is not checked, not unique, and an acquire with the same label does not resume an active lease.lease table of state.db, so they survive a daemon restart (a rebuild restarts it).screentext boxes, tap and swipe use one space: iOS screen points. A point is 2 native pixels on @2x iPhones and 3 on @3x ones, so an iPhone XR (828x1792) gives a 414x896 image. Plus models are the exception: they render at 1080 px for 414 points, and ghosthand knows the native size of each iPhone screen. Read a spot in the image, send the same numbers.| iPhone | Native pixels | Default (points) | Claude tokens | GPT tokens (32 px patches x1.2) |
| 6s (@2x) | 750x1334 | 375x667 | 336 | 303 |
| XR (@2x) | 828x1792 | 414x896 | 480 | 437 |
| 14 Pro (@3x) | 1179x2556 | 393x852 | 465 | 422 |
--scale (a fraction of native pixels) or GHOSTHAND_SCALE. Use the same value for every command, because it also changes how tap reads coordinates:ghosthand screenshot -o full.png --scale 1 # native pixels, 828x1792 ghosthand tap 414 896 --scale 1 # native pixel coordinates
screentext always runs OCR on native pixels (small text reads better), then scales the boxes.| Tradeoff | ghosthand | Appium / WDA |
| Phone setup | USB trust + Bluetooth pairing | Development setup + signed runner |
| Signing renewal | None; no runner installed | Free Personal Team: renew WDA provisioning every 7 days; paid membership avoids the weekly limit |
| Input | Mouse, keyboard, and wheel through AssistiveTouch | Native UI-testing gestures, including multi-touch |
| Find controls | Screenshots, OCR, coordinates | UI elements and attributes, plus screenshots and coordinates |
| Runtime dependencies | USB capture + Bluetooth link | Running WDA / XCTest session |
| App lifecycle | Navigate through the visible UI | Direct launch, terminate, and state queries |
| Text | US-ASCII only | Broader text support, depending on the field |
| Fleet size | Bluetooth limit: about 7 per Mac, 2 tested | No Bluetooth limit; depends on host resources and USB |
testmanagerd crashes. Here, Bluetooth can disconnect, USB capture can freeze or miss system dialogs, and private macOS APIs can change. Mouse drags are not always finger swipes, and there is no UI element tree or multi-touch. See Limits.| ghosthand | iPhone Mirroring | Appium (XCUITest) | |
| App on the iPhone | none | none | WebDriverAgent (signed) |
| Xcode, Developer Mode | no | no | yes |
| Screen | USB capture | Wi-Fi mirror | XCTest |
| Input | Bluetooth Classic HID | Mac input | XCTest |
| iOS 15 | yes over BLE (relative pointer); not tested over Classic | no (iOS 18+) | yes |
| Unlock with passcode | yes | no | no |
| iPhones per Mac | ~7, 2 tested | 1 | many |
| Account, cloud | none, local daemon | same Apple ID on Mac and iPhone | none |
acquire -d; each lease runs on its own iPhone:ghosthand list # 7EF219AD-... Morse's iPhone iPhone XR (iPhone11,8) iOS 18.7 (bluetooth connected, absolute pointer) # 42B874EC-... Test iPhone iPhone 6s (iPhone8,1) iOS 15.8.4 (bluetooth connected, relative pointer) ghosthand acquire -d 7EF219AD-69B4-423E-B8C4-4F4A6140822F # prints e.g. 42 ghosthand acquire -d "Test iPhone" # prints e.g. 43 ghosthand screenshot -l 42 -o a.png ghosthand tap -l 43 206 332 ghosthand release -l 42 ghosthand release -l 43
~/.ghosthand/state.db (see State database):capture id 7EF219AD-... ── saved once ──> UDID 00008020-... ──> lock state, BT address first match: the only new iPhone on USB, or else the only one with that name
list warns. Plug them in one at a time once.ghosthand rename "iPhone XR" # on the lease's iPhone # renamed "iPhone" to "iPhone XR". The id stays 7EF219AD-69B4-423E-B8C4-4F4A6140822F
list and acquire -d "iPhone XR" use the new name at once. The Bluetooth link stays connected (tested on iOS 18.7).| Limit | Value | Why |
| Bluetooth Classic | 7 connected devices | Apple: "seven is the maximum number of Bluetooth devices that can be connected to your Mac at once; three to four is a practical limit". Keyboard, trackpad and AirPods count too |
| USB | 127 devices per bus | Not the problem. Power is: use a powered hub, each iPhone charges while it is controlled |
| Screen capture CPU | not measured | one video stream per iPhone |
--url (see Remote daemon).# System Settings > General > About > Name, or: sudo scutil --set ComputerName "Lab Mac 1" sudo scutil --set LocalHostName "lab-mac-1" # optional: network name, no spaces
tap "Lab Mac 1", then Pair.listlist gets devices from macOS's QuickTime screen-capture device list, not from a Bluetooth scan. Keep the USB cable attached and trust the Mac once. A Bluetooth-only phone is not listed. Camera permission is required on the Mac; neither a Bluetooth connection nor AssistiveTouch is required just to list a phone. The first list asks for Bluetooth access, because it starts Bluetooth.7EF219AD-69B4-423E-B8C4-4F4A6140822F Morse’s iPhone (2) iPhone XR (iPhone11,8) iOS 18.7.10 (bluetooth connected, absolute pointer) USB capture ID name model and iOS (USB) Bluetooth link, pointer mode
7EF219AD-… after a rename, an iOS update, and a cable replug (tested). Save it and pass it with -d. Not tested across different Macs.error: No iPhone in macOS screen capture. USB check: - iPhone di Carla (2): on USB but not trusted (AMDeviceStartSession 0xe8000025). Unlock it and tap Trust on the iPhone; ...
list starts Bluetooth and reconnects paired phones:| State | Meaning |
connected | input works |
disconnected | paired; the Mac reconnects in about 2 s. If it stays, Bluetooth is off on the iPhone or it is out of range. The Mac cannot tell these apart |
not paired | pair from iPhone Settings > Bluetooth; the next input command waits for it |
PasswordProtected from iOS lockdown over the trusted USB connection using macOS's private MobileDevice.framework. It does not need a screen frame. [locked] means the passcode is required; its absence means lockdown reports unlocked. If the lock state cannot be read, the field is absent. Capture and lockdown IDs differ; see More iPhones for how they are matched.unlock does not use OCR. USB screen capture does not yield frames while this iPhone is locked, so it cannot inspect the passcode screen. The Bluetooth mouse and keyboard run a timed sequence:click ──> screen on ──> two fast swipes up ──> check USB lock state for 4 s ├─ unlocked by Face ID ──> done └─ still locked └──> type passcode once └──> check lock state
unlock polls the USB lock state for up to 4 s, returns if Face ID already unlocked the phone, then types the passcode once if it is still locked. It cannot confirm which screen is shown before typing.PasswordProtected) through the private MobileDevice.framework. list shows [locked]; unlock checks it before and after.screenshot and screentext check the lock state first.screentext can find a button label and its pixel box; the agent chooses the next tap based on that result.GET /v1/openapi.yaml. Any language with an HTTP client can drive it.S=~/.ghosthand/daemon.sock curl --unix-socket $S http://localhost/v1/devices curl --unix-socket $S -H 'content-type: application/json' \ -d '{"device":"default","label":"curl","reason":"reply to Anna"}' http://localhost/v1/leases # {"id":"42",…} L=http://localhost/v1/leases/42 curl --unix-socket $S $L/screenshot -o s.png curl --unix-socket $S -H 'content-type: application/json' \ -d '{"x":207,"y":448}' $L/tap # screen points, like the screenshot curl --unix-socket $S $L/assistive-touch # {"enabled":true} curl --unix-socket $S -X DELETE $L # release
/v1/leases/{lease}/ and run on the lease's iPhone. Unknown, expired, released or taken with force: lease-invalid (403). Acquire while held: device-leased (409); the detail shows the label, reason, acquire time and last call. Retry to wait.Accept: text/event-stream to get progress as server-sent events.application/problem+json with a stable code. In event-stream mode the status is 200 and the problem arrives as the final error event.# on the Mac with the iPhones GHOSTHAND_TOKEN=secret ghosthand daemon start --port 7420 --host 0.0.0.0 \ --tls-cert cert.pem --tls-key key.pem # anywhere else ghosthand --url https://mac.local:7420 --token secret --ca cert.pem list
who can reach the phone how local user who owns ~/.ghosthand ──> unix socket, file mode 0600 remote client ─────────────────────> TCP with --port: Bearer token, TLS off localhost
| Action | Effect |
ghosthand daemon stop | no screenshots, no input, until the next command starts it |
| unplug the cable | no screenshots and no input: every command finds the phone over USB first |
| iPhone: Settings > Bluetooth > the Mac > (i) > Forget This Device | no input until you pair again |
| iPhone: Settings > General > Transfer or Reset > Reset > Reset Location & Privacy | removes the USB trust of every computer |
unlock gets it per call; prefer a direct pipe to unlock --stdin, not an argument.cmd+space and cmd+h did nothing in tests.key home goes Home; key esc sends Escape. Neither is a promise of Back in Settings or Safari. AC Back (Consumer usage 0x0224) is not exposed because reliable iOS behavior has not been verified. Descriptors are unchanged.unlock tries to wake a locked iPhone; USB capture may still return no frame. An unlocked one with the screen off needs a tap from you.list stays at bluetooth disconnected.ghosthand forget (with a lease on that iPhone). It removes the Mac's bond (same as System Settings > Bluetooth > the iPhone > (i) > Forget This Device).ghosthand key home. It makes the Mac discoverable and waits.list works and the lock state is correct, but screenshot gets no frame and no error:error: No frame from Morse’s iPhone (2) after 8s (session running, 0 frames since open). ...
ghosthand daemon restart. It fixed a stuck capture that failed with Recording Stopped (AVFoundationErrorDomain -11808) (iOS 18.7).ghosthand unlock fails.ghosthand daemon stop| Entry | What it is |
Morse’s iPhone (2) | the iPhone screen over USB (what ghosthand uses) |
Morse’s iPhone (2) Camera | the iPhone camera (Continuity Camera), not the screen |
... Camera. Only the one on USB has a screen entry.CBClassicManager (Sources/ClassicBluetooth).Mac (daemon) iPhone ┌──────────────────────────────────┐ ┌─────────────────────────────┐ │ SDP record: HID, report map │ <──SDP query─── │ Settings > Bluetooth > Pair │ │ L2CAP 0x11 control (handshakes) │ <──opens─────── │ │ │ L2CAP 0x13 interrupt │ ──reports─────> │ AssistiveTouch │ │ report 1: mouse (absolute) │ │ pointer + clicks = touches │ │ report 7: mouse (relative) │ │ │ │ report 2: keyboard, 6: media │ │ │ └──────────────────────────────────┘ └─────────────────────────────┘
check: corner ──> move (80,120) pt ──> screenshot P1 corner ──> move (160,120) pt ──> screenshot P2 pointer found in P1 and P2 ──> gain = measured / computed (saved in state.db) tap: computed reports from the last known spot ──> 100 ms pause ──> click
addServiceWithData: takes the SDP record in bluetoothd's own element format, not the SDP wire format (reversed from bluetoothd).sendMsg:35 with kCBMsgArgDiscoverableState makes the Mac discoverable.CBClassicPeer.handleMsg:args: is swizzled to install them.CBL2CAPChannel must stay referenced: releasing it closes its socket, and the iPhone shows "Connection unsuccessful".USB lockdown BluetoothAddress ──── EC:CE:D7:A4:9B:C1 ────> Bluetooth HID link
~/.ghosthand/state.db holds SQLite state. Device matches and pointer modes are caches, one row per iPhone keyed by Apple's UDID. The lease table holds active leases, and lease_counter keeps the highest issued ID so IDs are never reused (see Leases).phone (USB) bluetooth_pointer (Bluetooth) ┌───────────────────────────────────┐ ┌──────────────────────────────────────┐ │ usb_udid PK │<───────│ usb_udid PK, FK, ON DELETE CASCADE │ │ screen_capture_id UNIQUE │ │ mode absolute | relative │ │ capture_matched_by / _at │ │ gain, screen_width_pt, _height_pt │ └───────────────────────────────────┘ │ report_map, found_at │ └──────────────────────────────────────┘
sqlite3 -header -column ~/.ghosthand/state.db 'SELECT * FROM phone; SELECT * FROM bluetooth_pointer' # usb_udid screen_capture_id capture_matched_by capture_matched_at # 00008020-000405C214BB002E 7EF219AD-69B4-423E-B8C4-4F4A6140822F only-new-phone 1790773434 # usb_udid mode gain screen_width_pt screen_height_pt report_map found_at # 00008020-000405C214BB002E absolute classic-a85efc997e025d8f 1790773436
| Table | Written when | If the row is missing |
phone | a command sees a new iPhone. capture_matched_by: only-new-phone or same-name (see More iPhones) | matched again the same way |
bluetooth_pointer | the first tap or swipe | iOS 17+: absolute again, no check. Older iOS: the pointer check runs on the next tap |
state.db, reconnects on the next command (tested).phone row (below).sqlite3, also while the daemon runs (it keeps no copy in memory). Turn on foreign_keys: the sqlite3 shell has it off, and without it the pointer row is not deleted with its phone.DB=~/.ghosthand/state.db sqlite3 $DB "PRAGMA foreign_keys = ON; DELETE FROM phone WHERE usb_udid = '00008020-000405C214BB002E'" # one iPhone sqlite3 $DB 'DELETE FROM bluetooth_pointer' # all pointer modes
phone row. Plug in same-named new phones one at a time.bluetooth_pointer row. ghosthand forget also does it, but it removes the Bluetooth bond too, so you must pair again.state.db. Resetting its counter can give a new lease an old ID.| iOS | Pointer | Tap | Accuracy |
| 18.7 | absolute: report 1 says "go to X, Y" | ~0.3 s | exact |
| 15.8 | relative over BLE (iOS ignored absolute X/Y); not tested yet over Classic | ~0.45 s | 0.2 pt mean, 0.4 pt max (40 targets) |
list shows it: (bluetooth connected, relative pointer).| iPhone | Last iOS | Pointer | Tap |
| 6s, 6s Plus, 7, 7 Plus, SE (1st gen) | 15 | relative over BLE (tested on 6s); absolute over Classic not tested | ~0.45 s relative, < 0.5 pt off |
| 8, 8 Plus, X | 16 | absolute tried first, not tested | |
| XS, XS Max, XR, SE (2nd gen, 2020) and newer | 17+ | absolute (XR tested) | ~0.3 s, exact |
tap 300,500 with the pointer at 40,120 (move +260,+380 pt) on a 6s: (+169,+248) (+170,+247) ── speed 300, past the flat end of the table ──> 214.9 pt each (+16,+24) ── speed 28 ─────────────────────────────────> 30.0 pt (0,-1) ── speed 1: 0.2 pt, lands within 0.2 pt 100 ms pause, then click ~0.45 s in total
gain (1.000 at the default speed) and scales the table by it. Other speeds are not tested.--duration: reports are spread over it and sized so the drag ends exactly at the target.xcode-select --install) build it too. Tested with Command Line Tools (Swift 6.1) and Xcode 26 (Swift 6.3).git clone https://github.com/remorses/ghosthand cd ghosthand swift build -c release cp .build/release/ghosthand /usr/local/bin/
npm/ is the npm package. pnpm build there compiles arm64 and x86_64 release builds, merges them with lipo into one universal npm/dist/ghosthand, and checks that ghosthand --version matches package.json. Bump ghosthandVersion in Sources/ghosthand/daemon.swift and the package version together.cd npm pnpm publish # prepublishOnly cleans dist and runs the build
CLI / curl / any language │ HTTP over ~/.ghosthand/daemon.sock (mode 0600, no token) │ HTTP or HTTPS over TCP with --port (Bearer token) v Hummingbird ──> generated API (openapi.yaml) ──> own thread ──> Controller │ ┌───────────────────────────────────────┬───────────────────┤ v v v FrameStream per iPhone (AVFoundation) Lockdown lock state HIDDevice: BT Classic OCR (Vision) (MobileDevice) HID, CBClassicManager
Sources/ghosthand/openapi.yaml is the source of truth. swift-openapi-generator builds the server and the client from it.unlock, taps) are serialized per iPhone. Different iPhones run in parallel.~/.ghosthand/daemon.sock, daemon.log, daemon.lock, state.db.