Skip to content
handsfree.SupportOpen Handsfree
Browse articles

Set up headless Linux

Install the self-contained host, open private setup over SSH, and connect your iPhone.

On this page

Handsfree can run on a Linux server without a desktop environment. You use a small private browser wizard on your laptop, then connect your iPhone over Tailscale. No repository clone, Node installation, or npm commands are required for the packaged app.

Before you begin#

Use a 64-bit Linux machine with glibc: Ubuntu 22.04 or newer / Debian 12 or newer are the initial targets. Choose x64 for Intel/AMD or arm64 for ARM. Alpine/musl and 32-bit Linux are not supported by these packages. You need a normal Linux account, SSH access, and outbound internet access to Clerk and your coding provider. Don’t run Handsfree as root.

For now, Claude Code handles phone execution. Codex installation, authentication, and runtime verification are available, but Codex phone execution is not enabled. Your provider subscription/credits are separate from your Handsfree account.

1. Download and install#

Get the matching handsfree-0.2.6-linux-x64.tar.gz or handsfree-0.2.6-linux-arm64.tar.gz and its .sha256 file from Handsfree downloads. These installer downloads are public; no repository access or clone is needed.

Copy both files to your Linux account with your usual SSH file transfer tool. In that folder, substitute arm64 below if appropriate:

sha256sum -c handsfree-0.2.6-linux-x64.tar.gz.sha256
tar -xzf handsfree-0.2.6-linux-x64.tar.gz
cd handsfree-0.2.6-linux-x64
./install.sh --service

Proceed only if the checksum says OK. The installer copies a self-contained package into ~/.local/opt/handsfree, creates ~/.local/bin/handsfree, and installs a user systemd service. Existing versions and user data are retained. It does not use sudo or install Tailscale or coding agents silently.

If your machine has no user systemd session, use ./install.sh without --service, then ~/.local/bin/handsfree start inside your own terminal multiplexer. This foreground mode stops when that process stops. For the service to survive logout and start at boot, ask your administrator whether user lingering is appropriate (loginctl enable-linger YOUR_LINUX_USERNAME). This is an explicit administrator choice, not something the installer changes.

2. Open private setup on your laptop#

From a terminal on your laptop, run this with your existing SSH alias or username@hostname:

ssh -N -L 19880:127.0.0.1:19880 -L 43821:127.0.0.1:43821 YOUR_LINUX_HOST

Leave that terminal open. In another SSH session on the Linux machine, run:

~/.local/bin/handsfree setup-url

Open the complete printed link in your laptop browser. Keep the link private; it grants administrative setup access through your tunnel. Use 127.0.0.1, not localhost, and keep the long #… suffix when opening it. Handsfree removes that suffix from browser history after loading. Refreshing the page intentionally clears its in-memory access token; reopen the full link to reconnect.

Only ports 19880 (setup) and 43821 (temporary sign-in callback) need SSH forwarding. Never expose either port with a firewall rule, Tailscale Serve, Funnel, or a public reverse proxy. The actual host listens on loopback 19879 and its agent daemon on 19878; the wizard gives only the host a private Tailscale HTTPS route.

3. Unlock and sign in#

Create a vault passphrase with at least 12 characters and save it in your password manager. Confirm it to avoid locking yourself out. The vault encrypts Handsfree OAuth credentials using scrypt and authenticated AES-256-GCM encryption. Its encryption key is held only in process memory. A restart always begins locked; there is no plaintext fallback or hidden saved passphrase.

Choose Create account / Sign in, then Continue in secure sign-in. Clerk opens in another browser tab. You can create an account there or use an existing one. Finish the email verification or supported provider login, approve Handsfree access, and return to setup. This internal release uses Clerk Development, not production.

Use the same Handsfree account on your iPhone. Clerk identity, your Tailscale account, and your coding-agent account are three separate things; signing into one doesn’t sign into the others.

4. Connect Tailscale#

Follow Tailscale’s Linux installation instructions. Authenticate this Linux machine and your iPhone to the same tailnet. In the wizard, choose Check setup again, then Enable private HTTPS. If Tailscale presents an HTTPS approval link, approve it and retry.

If this user cannot configure Serve, ask your administrator about Linux operator permissions. Handsfree never runs sudo. The wizard preserves existing routes and chooses an available HTTPS port; it refuses an address with public Funnel sharing enabled. It does not erase or reset your Tailscale configuration.

5. Verify your coding agent and choose projects#

Install and authenticate Claude Code on this Linux machine as the Handsfree user, following its official setup guide. Agent credentials on your laptop do not authenticate the Linux server. Use the provider’s own supported remote authentication instructions.

Choose Check setup again to confirm installation and login. Test response asks Claude for a fixed response without project tools or external MCP access; it uses provider credits. Enable Claude and review the agent-access consent before saving. Agents run as your Linux user and can execute commands: project selection is not an OS sandbox. Use a dedicated low-privilege Linux user if you need stronger separation.

Enter one or more absolute Linux search folders, such as /home/alex/Projects. Choose Find Git repositories, select the projects you want, and save. Discovery is read-only and supports normal repositories and Git worktrees. It skips hidden/dependency folders and is bounded to avoid a never-ending scan. Add a folder manually if it isn’t found or isn’t a Git repository.

6. Connect your iPhone#

Install the internal iPhone build from TestFlight and sign in to Handsfree. Ask Todd for internal tester access; there is no public TestFlight invitation link in this release.

Start the Linux host, then show a new pairing code. On your iPhone, turn on Tailscale and choose Add computer in Handsfree. Scan the QR code, or enter the private HTTPS address and code manually. The host verifies that both devices use the same Clerk account. A code expires after ten minutes and can be used once. The wizard confirms when a native iPhone connects. Send a small request to verify the complete agent path.

Personal voice history and connection diagnostics#

Linux 0.2.6 includes the same voice diagnostics screen as Mac. In your private setup page, select Open personal voice history while the vault is unlocked, you are signed in, and the host is running. The page opens through the existing SSH tunnel. Keep that setup link private; no new port or public dashboard is needed.

With iPhone build 26 or later, recognized text, matched keywords, decisions and recognition errors are captured automatically during normal voice use. No extra microphone recording or audio upload is started. Older build 25 requires manual capture. History belongs to the signed-in Handsfree account and its paired phones. Search, filter, expand events, export text logs or delete stored history. There is no global utterance feed. Mac and Linux retain the latest 1,000 events for up to seven days; pending iPhone events remain memory-only.

Locking the vault or switching accounts clears the displayed history on the next state poll (within two seconds when connected) and denies new reads immediately. Refreshing the diagnostics browser tab clears its access token: reopen it from setup. Exported transcript files are your copies and do not automatically expire.

Export safe connection diagnostics downloads content-free connection events, version and runtime status, separate from voice transcripts and raw host logs. Use that file first when reporting connection loss. Voice history can be disabled persistently in the iPhone command guide. See host parity for the shared release process and intentional differences between Mac and Linux.

Restarts, upgrades, and recovery#

  • Closing the browser or SSH tunnel does not stop a systemd-installed host. Restarting the Handsfree service does: unlock the vault and select Start host again.
  • To reopen setup, reconnect the SSH tunnel and run handsfree setup-url again. If your shell does not find the command, use ~/.local/bin/handsfree.
  • handsfree status, handsfree stop, and handsfree restart operate the user service. A stop disconnects phones and can interrupt agent work; finish active work first.
  • Install a new package with the same installer to upgrade. It switches a current symlink and keeps a previous symlink and version directories for administrator-assisted rollback. It never deletes your saved projects, vault, or host history. Upgrades restart the service into a locked state.
  • A wrong vault passphrase leaves the encrypted file untouched. Forgotten passphrases are not recoverable. Ask an administrator to back up the complete data directory before considering a fresh account vault.
  • “Address already in use”: close another Handsfree setup or Mac sign-in callback using the same laptop ports, or ask an administrator to resolve the conflict. Don’t expose setup publicly as a workaround.
  • “Different account”: sign out on the phone, then sign in with the exact email/account displayed by Linux setup. A new code alone won’t bypass the account check.
  • “Cannot reach host”: check both Tailscale connections, host running state, the private HTTPS route, and tailnet ACLs. The SSH tunnel is for setup, not the phone connection.

Access, logs, and removal#

The setup page lists paired phones and lets you revoke a phone’s host credential. Signing out on a phone disconnects that phone but does not delete the Clerk account or automatically revoke every host credential. Revoke a lost device from each host. Agent work already submitted may continue after the phone disconnects.

State is under ~/.local/share/handsfree; OAuth credentials are encrypted, while host history, configuration, and host device-token hashes use owner-restricted local files. Provider credentials remain in the provider’s storage. Logs are in logs/host.log; the service journal also contains the private setup link. Review/redact paths, account identifiers, messages, and links before sharing diagnostics.

To retire a host, first revoke its phones and stop active work. Stop and disable the user service with systemctl --user disable --now handsfree.service. The administrator can remove the matching unit and installed version directories later, preserving the data directory for backup. Remove only Handsfree’s specific Tailscale route after inspecting tailscale serve status; do not run a global Serve reset that would remove other apps’ routes.