Skip to main content

macOS chat-relay bridge: iMessage <-> Telegram, web UI, and pluggable integrations

Project description

chatwire

Relay iMessages from a macOS host to other places — currently a Telegram bot and a web UI, with more integrations planned.

Originally branded chat-bridge; renamed to chatwire for v0.2.0 because PyPI's similarity check rejected chat-bridge (collides with an unrelated chatbridge package).

Status: alpha. The author runs this daily; nobody else has installed it yet. Things will change. See docs/OPEN_SOURCE_PLAN.md for the roadmap.

What it does

  • Inbound. A small Python service polls ~/Library/Messages/chat.db, resolves senders against Contacts.app, and forwards messages (text, photos, videos, attachments) to your configured integrations.
  • Outbound. Reply from your phone, your laptop, anywhere — the service drives Messages.app via AppleScript to send back as you.
  • Group chats. First-class. Replies route by chat GUID, not the sender's 1:1 handle, so you can keep a group conversation in Telegram or the web UI and replies land back in the group.

Constraints

iMessage is Mac-only. The bridge has to live on a Mac with the user's Apple ID logged into Messages.app, granted Full Disk Access (to read chat.db) and Automation→Messages (to send). macOS gates both behind System Settings clicks that no installer can bypass — the setup wizard makes them as short as possible, but you will click through some prompts the first time.

Tested on macOS 12 Monterey. macOS 13–15 should work; not yet smoke-tested. See docs/OPEN_SOURCE_PLAN.md for the support matrix.

Install

Recommended path: pipx, against python.org's Python.

# Install python.org Python first if you don't have it:
#   https://www.python.org/downloads/macos/
# (Homebrew Python works but TCC treats it as a different identity —
# you'd have to grant Full Disk Access + Automation to that binary
# specifically. python.org is the well-trodden path.)

# Install pipx if you don't have it (once per machine):
python3 -m pip install --user pipx
python3 -m pipx ensurepath

# Install chatwire from PyPI:
pipx install --python /Library/Frameworks/Python.framework/Versions/Current/bin/python3 \
    chatwire

# Wire it up:
chatwire install-agents
chatwire setup

The setup wizard walks you through the Telegram bot token, the macOS permission grants (Full Disk Access + Automation→Messages), and writes ~/.chatwire/config.json.

Alternate install methods

Homebrew tap. Convenient if you already use brew.

brew install allenbina/tap/chatwire
chatwire install-agents
chatwire setup

Tap source: https://github.com/allenbina/homebrew-tap.

curl-pipe-bash. No PyPI access, no Homebrew, just a shell.

curl -fsSL https://raw.githubusercontent.com/allenbina/chatwire/main/scripts/install.sh | bash

Pin to a tag with CHATWIRE_REF=v0.2.0. The script refuses Xcode CLT's Python stub and warns on Homebrew Python (TCC identity protection). Same post-install steps (chatwire install-agents etc.).

Developer / git-clone path. For hacking on the bridge itself:

git clone https://github.com/allenbina/chatwire.git ~/projects/chatwire
cd ~/projects/chatwire
python3 -m venv .venv
.venv/bin/pip install -e .

# Render and load the launchd agents:
.venv/bin/chatwire install-agents

# (legacy installs only) one-shot migration from ~/.imessage-tg/.env:
.venv/bin/chatwire migrate

# Sanity check:
.venv/bin/chatwire doctor

Configure ~/.chatwire/config.json (chmod 600). Schema:

{
  "version": 1,
  "TELEGRAM_BOT_TOKEN": "...",
  "TELEGRAM_ALLOWED_USER_IDS": "123456789",
  "SELF_HANDLES": "+1XXXXXXXXXX,you@icloud.com",
  "WEB_PORT": "8723"
}

The setup wizard (Phase 2) will write this for you. Until then it's hand-edited.

macOS permissions

Both the FDA grant and the Automation→Messages grant need to be given to the python.org Python binary (not Homebrew's), because the python.org installer ships two Mach-O binaries with different code-signing identities that TCC tracks separately. See docs/REFERENCE_INSTALL.md section 5 for the full walkthrough — that section was the reason the bridge worked at all on the first install, and it's the same on every Mac.

scripts/check-permissions.sh (or chatwire doctor) will tell you which prompts you still need to click.

Web UI access

By default the web UI has no auth — anyone who can reach the URL can read and send messages. The intended posture is to gate access at the network layer (Tailscale, LAN-only, Cloudflare Access, etc.).

For setups where the URL leaks past that boundary, the wizard's Security step (or Settings → Web UI password) sets an optional shared password. It's a single password (not multi-user) stored as a PBKDF2-SHA256 hash in ~/.chatwire/config.json; sessions are signed cookies that expire after 30 days. Forgot it? Stop the web agent, edit config.json (already chmod 600), drop the web.auth block, restart.

Privacy

No telemetry. chatwire collects no analytics, sends no usage data, and includes no third-party SDKs that report back. Your messages, contacts, and chat.db stay on your Mac; outbound traffic only goes to integrations you configure (e.g. Telegram via your own bot token).

Two narrow third-party requests the web UI does make, neither carrying any of your data:

  • The update-check banner fetches api.github.com/repos/<repo>/releases/latest once a day to surface new-version notices. Disable by setting UPDATE_CHECK_REPO="" in the launchd agent's environment.
  • Static assets (htmx, emoji-picker-element) load from unpkg.com and cdn.jsdelivr.net.

Repo layout

bridge.py             telegram bot + outbound (TG -> iMessage)
chat_db.py            reads chat.db, HEIC -> JPEG via sips
chat_send.py          osascript wrappers (send_text, send_file)
prefix.py             message prefix formatter + reply parser
config.py             config.json loader (with .env fallback)
chatwire_cli.py       setup / install-agents / logs / doctor / migrate
contacts.py           Contacts.app -> handle/name lookup
echo_log.py           cross-process echo dedup
whitelist.py          runtime-mutable allowlist
_version.py           release-semver source of truth
web/                  FastAPI web UI + first-run setup wizard
migrations/           config-schema migration runner
templates/launchd/    plist templates rendered by install-agents
scripts/install.sh    curl-pipe-bash installer (alternative to brew)
docs/                 OPEN_SOURCE_PLAN.md, REFERENCE_INSTALL.md

Trademarks

iMessage, Messages, macOS, and AppleScript are trademarks of Apple Inc., referenced here in their descriptive sense — this project relays to and from Apple's iMessage service. chatwire is not affiliated with, endorsed by, or sponsored by Apple Inc.

License

MIT — see LICENSE.

Contributing

Not accepting PRs yet — Phase 1 is mid-flight. Open an issue if you have questions or hit a wall installing.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

chatwire-0.9.1.tar.gz (124.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

chatwire-0.9.1-py3-none-any.whl (141.6 kB view details)

Uploaded Python 3

File details

Details for the file chatwire-0.9.1.tar.gz.

File metadata

  • Download URL: chatwire-0.9.1.tar.gz
  • Upload date:
  • Size: 124.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for chatwire-0.9.1.tar.gz
Algorithm Hash digest
SHA256 ff9739d59150f5cb47eef0dc825bfde24619bb7af4ab81d7e259d887af621a1e
MD5 72dabac38ae753c76a2f42e189225afb
BLAKE2b-256 2b9d7396fe452c62485fe6ab4453b2f985c1c5a05544d25d697a10962778f68f

See more details on using hashes here.

Provenance

The following attestation bundles were made for chatwire-0.9.1.tar.gz:

Publisher: publish.yml on allenbina/chatwire

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chatwire-0.9.1-py3-none-any.whl.

File metadata

  • Download URL: chatwire-0.9.1-py3-none-any.whl
  • Upload date:
  • Size: 141.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for chatwire-0.9.1-py3-none-any.whl
Algorithm Hash digest
SHA256 fb6bd76551ff606931eaf16f50411b55eb4e204e0caa068da4cb7645b5bc1839
MD5 d257b3b358b68abc10449d5efe073d4b
BLAKE2b-256 9494da6fa6e6c427a1bdb2dd757d6f17993963092616fb7a3d6b6844eb81cc2d

See more details on using hashes here.

Provenance

The following attestation bundles were made for chatwire-0.9.1-py3-none-any.whl:

Publisher: publish.yml on allenbina/chatwire

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page