Skip to content

Repository files navigation

Reattach

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.

Concept

┌─────────────────┐
│   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

Components

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

Requirements

Installation

1. Install reattachd

Option A: Homebrew (macOS)

brew tap kumabook/reattach
brew install reattachd

To run it as a background service:

brew services start reattachd

Default mode: This binds to 127.0.0.1:8787 over plain HTTP. To enable Tailscale auto-configuration (HTTPS + tailnet bind) via brew services, see Tailscale + brew services below.

Option B: Install script (macOS / Linux)

curl -fsSL https://raw.githubusercontent.com/kumabook/Reattach/main/install.sh | sh

2. Setup daemon

macOS (launchd)

# 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

Linux (systemd)

# 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 reattachd

3. Configure network access

Choose how your iOS device will connect to reattachd:

Tailscale (recommended)

The simplest setup — a single command handles TLS certificates, QR code generation, and server startup:

sudo reattachd --tailscale

This 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: sudo is required on Linux because tailscale cert needs root access to generate certificates.

To register additional devices later:

sudo reattachd --tailscale setup

Tailscale + brew services

brew 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 reattachd

Caveat: brew services restart and brew upgrade reattachd regenerate 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 via sudo reattachd --tailscale and managing the daemon with your own launchd plist (see the manual setup section above).

Manual TLS

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.pem

Or via environment variables:

REATTACHD_TLS_CERT=/path/to/cert.pem REATTACHD_TLS_KEY=/path/to/key.pem reattachd

Local network

Use your machine's local IP address directly. No additional setup required.

URL: http://192.168.x.x:8787

The iOS app sets NSAllowsLocalNetworking so 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's 100.64.0.0/10 range — connect over Tailscale via --tailscale (HTTPS) instead.

Cloudflare Tunnel

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 reattach
URL: 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.

4. Install iOS app

Download from the App Store, or build from source (see Development).

Usage

Start a tmux session

tmux

You can also name the session and set the working directory:

tmux new-session -s myproject -c ~/projects/myproject

Register your device

Generate 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 --tailscale with no devices registered, the QR code is shown automatically at startup.

Control from iOS

  1. Open the Reattach app
  2. Your tmux sessions appear in the list
  3. Tap a session to view output and send input

Development

Requirements

  • Rust
  • Xcode (for iOS app)
  • Apple Developer account (for push notifications)

Build from source

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 start

Configuration

config.local.mk

APNS_KEY_PATH = /path/to/AuthKey.p8
APNS_KEY_ID = XXXXXXXXXX
APNS_TEAM_ID = XXXXXXXXXX
APNS_BUNDLE_ID = tokyo.kumabook.tmux.reattach

ios/Reattach/Config.xcconfig

BASE_URL = https:/$()/your-domain.example.com

Makefile Commands

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"]

Build iOS app

Open ios/Reattach.xcodeproj in Xcode and build to your device.

Security

⚠️ Use at your own risk. Reattach allows remote command execution on your machine. Please understand the security implications before using this software.

Network Binding

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)

TLS

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.

Authentication

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

Cloudflare Tunnel (Recommended for remote access)

When exposing reattachd to the internet via Cloudflare Tunnel, we strongly recommend adding an extra layer of security with Cloudflare Zero Trust:

  1. Create an Access Application for your tunnel hostname
  2. Configure authentication policies (e.g., email OTP, SSO)
  3. 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.

Recommendations

  • 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

License

MIT

About

Continue your tmux-based dev sessions remotely

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages