Send files or directories to Karson's phone (Energetic Papaya / iPhone) via LocalSend. ALWAYS use this skill — without asking — whenever the user asks to send, transfer, share, push, or move ANY file(s) or folder(s) from this PC to their phone / mobile / iPhone / LocalSend / Energetic Papaya. Trigger on phrases like "send to phone", "send to my phone", "transfer to phone", "share to phone", "push to phone", "localsend this", "send this file", "send these files", "send the vault", "send the logs", "send the screenshot", and any rephrasing of the same intent. This is the ONLY approved way to move files from this PC to the phone — do not use alternatives unless the user explicitly asks for one.
Send one or more files (or entire directories) from this PC to Karson's phone (Energetic Papaya, iPhone) using the LocalSend v2 HTTP API via curl.
Use this skill automatically — without asking for confirmation — any time the user wants to move a file, folder, screenshot, archive, log, document, or any other artifact from this PC to their phone. Phrasing examples that MUST trigger this skill:
If the user says "try again" or "resend" in the context of a recent phone transfer, re-run this skill with the same file(s).
Determine absolute path(s) of the file(s) or director(ies) the user wants to send. Resolve relative paths against the current working directory. If the user describes a file without a path ("send the screenshot I just took"), find it first.
Confirm every path exists before calling the script — the script will also check, but failing early gives a better message.
You MUST print this exact block in your response before the Bash tool call so the user immediately sees a transfer is starting. Do not abbreviate, do not skip, do not replace with a one-liner. The border and emoji make it visually unmissable in the chat stream.
📱📱📱📱📱📱📱📱📱📱📱📱📱📱📱📱📱📱📱📱
>>> LOCALSEND TRANSFER STARTING <<<
📱📱📱📱📱📱📱📱📱📱📱📱📱📱📱📱📱📱📱📱
Destination : Energetic Papaya (iPhone)
Protocol : LocalSend v2 over HTTPS
Retry budget: 150 seconds (2.5 min grace)
Files :
- <file 1 basename> (<size>)
- <file 2 basename> (<size>)
...
Total : <count> file(s), <total size>
📱📱📱📱📱📱📱📱📱📱📱📱📱📱📱📱📱📱📱📱
Fill in the <...> placeholders with real values. Always print it — even for a single small file.
bash ~/.claude/skills/send-to-phone/scripts/send.sh <path1> [path2] ...
Required Bash tool parameters:
timeout: 200000 (200 seconds — the script itself caps retries at 150s plus upload time)run_in_background — the user needs to see progress synchronouslyPass paths as separate arguments. Directories are auto-archived to .tar.gz before sending.
.tar.gz archive that needs extraction (Files app on iOS, or iZip).The script keeps trying to reach the phone and complete prepare-upload for a full 150 seconds before giving up. This gives the user a grace period to unlock the phone, open LocalSend, or tap Accept if Quick Save is temporarily off. Specifically:
Do not shorten these timeouts. They are deliberate — large files over slow Wi-Fi and locked-screen handshakes both need the headroom.
The localsend Go CLI dev build installed at /usr/local/bin/localsend is broken — it returns Fail to get device info error="Not Found" even when the phone is reachable and the HTTPS API is responding correctly. Do not use the CLI. Our script bypasses it and uses the LocalSend v2 HTTP API directly via curl:
GET /api/localsend/v2/info on each known IP to pick a reachable onePOST /api/localsend/v2/prepare-upload with sender info + file manifest (phone auto-accepts when Quick Save is On)POST /api/localsend/v2/upload?sessionId=X&fileId=Y&token=Z for each file bodyThe session from step 2 expires within seconds of idle, so the script does prepare + upload back-to-back.
send.sh)fileType is a category enum, NOT a MIME type. The prepare-upload manifest's fileType field must be one of: image, video, audio, pdf, apk, text, other. Passing a raw MIME string (text/markdown, application/json, etc.) causes iOS LocalSend to misroute the payload into its in-app message viewer — the phone shows a "Patchy Server sent you a message" popup with an empty body, and the server returns HTTP 204 which looks like "Quick Save is off." The ls_category() helper in scripts/send.sh does the MIME → category mapping; do not bypass it."text" for document files. Even though text is a valid enum value, iOS LocalSend routes it to the message viewer (same blank-popup symptom). Send .md, .log, .txt, .json, .yaml, etc. as "other" so they arrive as downloadable files. ls_category() already does this — keep it that way..mp4/.mov as "video". iOS LocalSend routes "video" payloads to the Photos app, which rejects any container other than mp4/mov-h264 with "unsupported file format". .mkv, .avi, .webm, .m4v, and other video containers MUST be sent as "other" so they land in the Files app (which accepts any format). ls_category() enforces this — do not weaken the check.prepare-upload and the first upload call.prepare-upload returns 204 and the phone shows a system accept prompt; the retry loop will keep retrying within the 150s budget.curl -k required)The script tries the primary IP first and falls back automatically if it can't reach the API.
| Script exit code | Meaning | Fix |
|---|---|---|
| 1 | No files / file not found | Check the path you passed |
| 2 | Phone not reachable on any IP within 150s | Confirm LocalSend is open on phone, same Wi-Fi, and ping the phone |
| 3 | prepare-upload never returned 200 within 150s | Ensure Quick Save = On on the phone; check manifest validity |
| 4 | Phone declined the transfer (403) | Check LocalSend permissions; retry |
| 5 | Some files uploaded, some failed | Rerun; check per-file HTTP codes in stderr |
| Symptom on phone | Likely cause | Fix |
|---|---|---|
| "Patchy Server sent you a message" popup with blank/empty body | fileType was sent as a raw MIME (e.g. text/markdown) or as "text" — iOS routed it into the message viewer instead of the file receiver | Confirm ls_category() in scripts/send.sh is mapping MIME → category enum (image/video/audio/pdf/apk/other) and that .md/.log/.txt/etc. files resolve to "other". Never put raw mime into files[fid]["fileType"]. |
| Script prints "Phone returned 204 No Content — Quick Save is off" but Quick Save IS on | Could be the fileType-enum bug above (server 204's when it can't parse/accept the manifest), not actually a Quick Save issue | Check the fileType values in build_prepare_json before blaming Quick Save. |
| Script exits 0 but file never appears on phone | Uploaded to a stale session, or phone dismissed the message-viewer popup | Rerun; verify fileType enum mapping; check LocalSend history on phone |
If all IPs fail, have the user open LocalSend → Settings → Server info to read the current IPs. Update PRIMARY_IP / FALLBACK_IPS in scripts/send.sh if they've changed permanently.
localsend Go CLI (localsend send ...) — it's a broken dev build.send.sh.