Skip to content

mihaelamj/iRelay

Repository files navigation

iRelay

iRelay — text your Mac, run an AI agent

Text your Mac. Run an AI agent.

A Swift daemon that turns iMessage into a remote terminal for Claude Code. Send a message from your phone, your Mac picks it up, spawns Claude Code in your project directory, and texts you back the result.

No terminal. No SSH. No laptop open. Just iMessage.

Blog Post Swift Platform License

Demo

iRelay Demo
Creating a GitHub repo from iMessage while walking around the house

How It Works

iPhone (iMessage) → Mac (iRelay daemon) → Claude Code → response → iMessage

Send something like irelayy fix the failing test from your phone. Your Mac runs Claude Code against your project and texts you back what it did.

No web UI, no port forwarding, no VPN. iMessage as a transport layer.

Important: The Mac running iRelay must be signed into a different Apple ID than the device you message it from. You're sending an iMessage between two separate accounts — your phone texts the Mac, not itself.

Each response is prefixed with session info: iRelay [session-id] #message-number (context-size). Sessions persist across messages so context carries over. Built-in commands:

  • irelayy clear / reset — wipe session and start a new one (new session ID)
  • irelayy save — persist session to ~/.irelay/sessions/ as markdown

Architecture

block-beta
  columns 1
  block:gateway["iRelay Gateway (Hummingbird HTTP Server)"]
    columns 3
    SM["Session Manager"] AR["Agent Router"] CS["Cron Scheduler"]
  end
  block:channels["Channels"]
    columns 5
    iMessage Telegram Slack Discord more1["..."]
  end
  block:providers["LLM Providers"]
    columns 4
    Claude OpenAI Ollama Gemini
  end
  Storage["Storage (GRDB/SQLite)"]
Loading

Channels

Channel Status Transport
iMessage ✅ Tested Messages.framework / AppleScript
Telegram 🚧 Untested Bot API (HTTPS + long polling / webhook)
Slack 🚧 Untested Web API + Events API / Socket Mode
Discord ⚠️ Partial (#45) REST send works, Gateway receive TBD
Signal 🚧 Untested signal-cli subprocess
Matrix 🚧 Untested Client-Server API + /sync polling
IRC 🚧 Untested Raw TCP (Foundation streams)
WebChat 🚧 Untested Hummingbird REST + HTML UI
WhatsApp 🚧 Untested Business Cloud API + webhook

Not planned: Email, SMS/Twilio, Microsoft Teams, Google Chat, Facebook Messenger, Mattermost, Line, Viber, Zulip.

LLM Providers

Provider Status Streaming
Claude ✅ Tested SSE via URLSession
OpenAI 🚧 Untested SSE via URLSession
Ollama 🚧 Untested NDJSON (no tool support)
Gemini 🚧 Untested SSE via URLSession

Only Claude is wired into serve and agent-bridge commands today. The other three providers compile and implement the LLMProvider protocol but are not yet registered in any CLI command.

Core Modules

Module Status Notes
Gateway ✅ Working Hummingbird HTTP (webhooks, health, status)
Sessions ✅ Working GRDB-backed, persistent
Agents ✅ Working Routing, history, streaming
AgentSpawner ✅ Working Subprocess execution with concurrency limits
Storage ✅ Working GRDB/SQLite with migrations
Networking ✅ Working HTTP client + SSE streaming
Security ✅ Working macOS Keychain
Services ✅ Working Full orchestration pipeline
Voice ✅ Working macOS say command
MCPSupport ✅ Working JSON-RPC stdio client
Memory ⚠️ Partial (#49) FTS5 search works, vector embeddings TBD
Scheduling ⚠️ Partial (#50) Interval/daily works, cron parsing TBD

Build

make build          # release build
make build-debug    # debug build
make test           # run tests
make lint           # swiftlint
make format         # swiftformat
make install        # install to /usr/local/bin

CLI

irelay serve            # start gateway + all channels
irelay chat             # interactive CLI chat
irelay agent-bridge     # iMessage ↔ Claude Code bridge

TBD:

  • irelay config — manage agents, channels, providers (#46)
  • irelay status — show gateway + channel status (#47)
  • irelay daemon install/uninstall — LaunchAgent management (#48)

Apps

TBD:

  • macOS menu bar app (#51)
  • iOS app (#52)

Project Structure

Extreme Packaging — single Package.swift in Packages/, Main.xcworkspace at root. 29 SPM library targets, 1 executable.

iRelay/
├── Packages/
│   ├── Sources/
│   │   ├── Shared/             # Models, config, constants
│   │   ├── Storage/            # GRDB/SQLite persistence
│   │   ├── Networking/         # HTTP, SSE, WebSocket helpers
│   │   ├── Gateway/            # Hummingbird HTTP server
│   │   ├── Sessions/           # Session management + routing
│   │   ├── Agents/             # Agent config + multi-agent routing
│   │   ├── ChannelKit/         # Channel protocol (abstraction)
│   │   ├── IMessageChannel/    # Native iMessage
│   │   ├── TelegramChannel/    # Telegram Bot API
│   │   ├── ...                 # 7 more channel implementations
│   │   ├── ProviderKit/        # LLM provider protocol (abstraction)
│   │   ├── ClaudeProvider/     # Anthropic Messages API
│   │   ├── ...                 # 3 more provider implementations
│   │   ├── Voice/              # macOS TTS
│   │   ├── Memory/             # FTS search + recall
│   │   └── CLI/                # ArgumentParser entry point
│   └── Tests/
├── Apps/                       # macOS + iOS app targets (TBD)
└── Main.xcworkspace

See ARCHITECTURE.md for full details — protocols, dependency graph, and implementation notes.

Requirements

  • Swift 6.0+
  • macOS 14+ (Sonoma) / iOS 17+
  • Xcode 16+

Why the Double Y

Two daemons on the same Mac listening to iMessage would fight over every message. iRelay claims any message starting with irelayy (double y). Everything else gets ignored. Simple namespace partitioning over a shared channel.

Blog Post

Read the full writeup: iRelay: Text Your Mac, Run an AI Agent

License

MIT

About

Apple-native personal AI assistant. Pure Swift. macOS + iOS.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors