Reattach is a remote tmux client for iOS — control your Mac's terminal sessions from anywhere.
With optional coding agent integration, get push notifications when Claude Code or other AI assistants need your input.
┌─────────────────┐
│ iOS App │
│ (iPhone/iPad) │
└────────┬────────┘
│ HTTPS
▼
┌─────────────────┐
│ reattachd │──────► tmux
│ (Rust daemon) │
└─────────────────┘
Your machine
- Remote tmux access: View and control tmux sessions from your iPhone/iPad
- Secure access: Built-in TLS support with Tailscale auto-configuration, or use Cloudflare Tunnel
- Coding agent friendly: Optional hooks for Claude Code / Codex push notifications
- Simple architecture: reattachd is just a thin wrapper around tmux
| Component | Description |
|---|---|
reattachd |
Rust daemon that exposes tmux sessions via HTTP API |
ios/ |
iOS app for remote session control |
hooks/ |
Optional hooks for coding agent notifications |
launchd/ |
macOS service configuration |
- macOS or Linux
- tmux
- Tailscale (recommended for remote access) or Cloudflare Tunnel
brew tap kumabook/reattach
brew install reattachdTo run it as a background service:
brew services start reattachdDefault mode: This binds to
127.0.0.1:8787over plain HTTP. To enable Tailscale auto-configuration (HTTPS + tailnet bind) viabrew services, see Tailscale + brew services below.
curl -fsSL https://raw.githubusercontent.com/kumabook/Reattach/main/install.sh | sh# Create log directory
mkdir -p ~/Library/Logs/Reattach
# Create plist file
cat > ~/Library/LaunchAgents/com.kumabook.reattachd.plist << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.kumabook.reattachd</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/reattachd</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>~/Library/Logs/Reattach/reattachd.log</string>
<key>StandardErrorPath</key>
<string>~/Library/Logs/Reattach/reattachd.error.log</string>
<key>EnvironmentVariables</key>
<dict>
<key>REATTACHD_PORT</key>
<string>8787</string>
<!-- Uncomment to allow local network access (default: 127.0.0.1) -->
<!-- <key>REATTACHD_BIND_ADDR</key> -->
<!-- <string>0.0.0.0</string> -->
<key>PATH</key>
<string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
</dict>
</dict>
</plist>
EOF
# Load and start
launchctl load ~/Library/LaunchAgents/com.kumabook.reattachd.plist# Create service file
sudo tee /etc/systemd/system/reattachd.service << 'EOF'
[Unit]
Description=Reattach Daemon
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/reattachd
Restart=always
Environment=REATTACHD_PORT=8787
# Uncomment to allow local network access (default: 127.0.0.1)
# Environment=REATTACHD_BIND_ADDR=0.0.0.0
[Install]
WantedBy=multi-user.target
EOF
# Enable and start
sudo systemctl daemon-reload
sudo systemctl enable reattachd
sudo systemctl start reattachdChoose how your iOS device will connect to reattachd:
The simplest setup — a single command handles TLS certificates, QR code generation, and server startup:
sudo reattachd --tailscaleThis auto-detects your Tailscale hostname and IP, generates TLS certs via tailscale cert, binds to the Tailscale IPv4 address on port 8787, and shows a QR code if no devices are registered. Just scan and go.
Note:
sudois required on Linux becausetailscale certneeds root access to generate certificates.
To register additional devices later:
sudo reattachd --tailscale setupbrew services does not pass through CLI arguments, so the default Homebrew
service runs without --tailscale. To enable Tailscale auto-configuration via
brew services, edit the brew-managed plist to inject the flag:
brew services stop reattachd
# Edit ~/Library/LaunchAgents/homebrew.mxcl.reattachd.plist
# Add "--tailscale" to ProgramArguments:
# <key>ProgramArguments</key>
# <array>
# <string>/opt/homebrew/bin/reattachd</string>
# <string>--tailscale</string>
# </array>
brew services start reattachdCaveat:
brew services restartandbrew upgrade reattachdregenerate the plist from the Formula, wiping out manual edits. You'll need to re-apply the change after any upgrade. If you upgrade frequently, consider running reattachd directly viasudo reattachd --tailscaleand managing the daemon with your own launchd plist (see the manual setup section above).
If you have your own TLS certificates (e.g., from Let's Encrypt):
reattachd --tls-cert /path/to/cert.pem --tls-key /path/to/key.pemOr via environment variables:
REATTACHD_TLS_CERT=/path/to/cert.pem REATTACHD_TLS_KEY=/path/to/key.pem reattachdUse your machine's local IP address directly. No additional setup required.
URL: http://192.168.x.x:8787
The iOS app sets
NSAllowsLocalNetworkingso plain HTTP is permitted to RFC1918 addresses (10.x.x.x,192.168.x.x,172.16–31.x.x) for local development. This exception does not cover Tailscale's100.64.0.0/10range — connect over Tailscale via--tailscale(HTTPS) instead.
For secure remote access without exposing ports, set up Cloudflare Tunnel:
# Create tunnel
cloudflared tunnel create reattach
# Configure tunnel (edit ~/.cloudflared/config.yml)
tunnel: reattach
credentials-file: /path/to/credentials.json
ingress:
- hostname: your-domain.example.com
service: http://localhost:8787
- service: http_status:404
# Start tunnel
cloudflared tunnel run reattachURL: https://your-domain.example.com
Security: Since Reattach allows remote command execution, you should configure authentication via Cloudflare Zero Trust. Add an Access Application policy to restrict access to your tunnel hostname.
Download from the App Store, or build from source (see Development).
tmuxYou can also name the session and set the working directory:
tmux new-session -s myproject -c ~/projects/myprojectGenerate a QR code to register your iOS device:
# With Tailscale (auto-detects URL)
sudo reattachd --tailscale setup
# Manual URL
reattachd setup --url <your-url>Scan the QR code with the Reattach iOS app to complete registration.
Tip: When using
reattachd --tailscalewith no devices registered, the QR code is shown automatically at startup.
- Open the Reattach app
- Your tmux sessions appear in the list
- Tap a session to view output and send input
- Rust
- Xcode (for iOS app)
- Apple Developer account (for push notifications)
git clone https://github.com/kumabook/Reattach.git
cd Reattach
# Copy sample configs
cp config.local.mk.sample config.local.mk
cp ios/Reattach/Config.xcconfig.sample ios/Reattach/Config.xcconfig
# Edit with your values
vim config.local.mk # APNs credentials
vim ios/Reattach/Config.xcconfig # Server URL
# Build and install daemon
make build
make install
make startAPNS_KEY_PATH = /path/to/AuthKey.p8
APNS_KEY_ID = XXXXXXXXXX
APNS_TEAM_ID = XXXXXXXXXX
APNS_BUNDLE_ID = tokyo.kumabook.tmux.reattachBASE_URL = https:/$()/your-domain.example.com
make build # Build reattachd
make install # Install launchd services
make uninstall # Remove launchd services
make start # Start services
make stop # Stop services
make restart # Restart services
make reinstall # Rebuild, reinstall, and restart
make logs # View logs
make status # Check service status
# Recommended: auto-install Claude Code + Codex notification hooks
reattachd hooks install
# Manual setup (if you prefer direct config edits):
# ~/.claude/settings.json -> add both:
# hooks.Stop (matcher: "")
# hooks.Notification (matcher: "permission_prompt")
# each command: "reattachd notify"
# ~/.codex/config.toml (top-level) -> notify = ["reattachd", "notify"]Open ios/Reattach.xcodeproj in Xcode and build to your device.
reattachd binds to 127.0.0.1:8787 by default (localhost only). This is secure by default - only local processes and tunnels can access the API.
When using --tailscale, the bind address defaults to the host's Tailscale IPv4 address (e.g. 100.x.y.z) so the daemon is only reachable over the tailnet interface. Override with REATTACHD_BIND_ADDR if you want a different interface — use 0.0.0.0 only if you understand the exposure, since Tailscale certs are publicly valid Let's Encrypt certs.
To change the port or bind address:
REATTACHD_PORT=9000 reattachd
REATTACHD_BIND_ADDR=0.0.0.0 reattachd # Listen on all interfaces (use with caution)reattachd supports built-in TLS via --tailscale (auto-generates certs) or --tls-cert/--tls-key (manual PEM files). When TLS is not configured, the server runs plain HTTP — use a reverse proxy like Cloudflare Tunnel for HTTPS in that case.
reattachd includes device-based authentication:
- Devices must be registered via QR code (setup token)
- Each device receives a unique token for API access
- Unregistered devices cannot access the API
When exposing reattachd to the internet via Cloudflare Tunnel, we strongly recommend adding an extra layer of security with Cloudflare Zero Trust:
- Create an Access Application for your tunnel hostname
- Configure authentication policies (e.g., email OTP, SSO)
- Enable the Cloudflare Access service token or identity verification
This provides defense-in-depth: even if someone obtains a device token, they still need to pass Cloudflare's authentication.
- Use HTTPS (via
--tailscale,--tls-cert/--tls-key, or Cloudflare Tunnel) - Regularly review registered devices (
reattachd devices list) - Revoke unused devices (
reattachd devices revoke <id>) - Monitor reattachd logs for suspicious activity
MIT