Skip to main content

Discord and Telegram to tmux session bridge for agent-driven workflows.

Project description

tetherly icon

tetherly

Discord / Telegram channel ↔ tmux session bridge.

📖 Full documentation: docs/. Start with Getting Started, then Command Reference, Architecture, and Security. This README is a quick start.

Features

Same slash commands work in both Discord and Telegram:

  • /bind <session>: bind the current chat to a tmux session
  • /unbind: release this chat from its tmux session
  • /config: toggle plain-text auto-send (Discord auto_send:true|false, Telegram /config on|off) and trust_chat to let every member of a chat run commands without enumerating user IDs (owner-only)
  • /send <text>: send text plus Enter into the bound tmux session
  • /key <Enter|Escape|Ctrl-C|Ctrl-D|Tab|Up|Down|Left|Right>: send a special key
  • /tail [lines]: fetch recent tmux output
  • /status: inspect the current binding and tmux session status
  • Quick keys (no arguments): /enter, /esc, /ctrlc, /ctrld, /tab
  • Inline buttons on Codex / Claude Code alerts and on /status / /tail: tap [Enter], [Yes], [Refresh], [Stop] directly in chat — no typing needed

CLI helpers (run from inside a tmux session):

  • tetherly send --message <text>: forward a reply to whichever chat (Discord or Telegram) is bound to the session
  • tetherly codex-stop / tetherly codex-permission-request: Codex hook handlers that route messages to the bound chat
  • tetherly claude-stop / tetherly claude-notification: Claude Code hook handlers (Stop, Notification)

A tmux session is globally unique across platforms — it can be bound to one Discord channel or one Telegram chat, not both. Run /unbind first to move it.

Requirements

  • Python 3.11+
  • tmux installed
  • A Discord bot token and/or a Telegram bot token (at least one)

Setup

Install once on your machine:

pipx install tetherly
# or: uv tool install tetherly
tetherly init

tetherly init is interactive. It writes ~/.tetherly/.env and lets you enable Discord, Telegram, or both. It also asks where to install hooks for Codex and Claude Code (separately, so you can pick a different scope per CLI):

  • Global — writes once to ~/.codex/hooks.json or ~/.claude/settings.json. Hooks fire in every project automatically.
  • Project — skip global hooks and run tetherly install-hooks / tetherly install-claude-hooks inside each project.
  • Skip — don't touch the agent CLI's hooks.

Then start the bot(s):

tetherly

A single process runs whichever bots are configured. State lives at ~/.tetherly/state.json so one process serves every project.

Per-project usage

For each project you want to drive from chat:

tmux new -s <session-name>
# then in the bound chat:
#   /bind <session-name>            (Telegram)
#   /bind session:<session-name>    (Discord)
#   /config on   (Telegram)  /  /config auto_send:true   (Discord)

If you chose Project mode during init, also run once per project:

cd <project>
tetherly install-hooks            # Codex
tetherly install-claude-hooks     # Claude Code

Both accept --global to (re)install user-level hooks instead.

Sending from inside a session

tetherly send --message "작업 끝났습니다"
cat result.txt | tetherly send --stdin
tetherly send --session t1 --message "..."   # explicit session

tetherly send automatically routes to whichever chat (Discord or Telegram) the session is bound to. The legacy tetherly discord-send is still accepted as an alias.

Configuration

tetherly init writes everything you need. Advanced overrides live in ~/.tetherly/.env or shell env.

Discord

Variable Default Notes
DISCORD_BOT_TOKEN Bot token (required to enable Discord)
TETHERLY_ALLOWED_USER_IDS Comma-separated user IDs
TETHERLY_ALLOWED_GUILD_IDS Restrict commands to these guilds
TETHERLY_ALLOWED_ROLE_IDS Allow members holding any of these roles
TETHERLY_TEST_GUILD_ID Dev guild for instant slash-command sync

Telegram

Variable Default Notes
TELEGRAM_BOT_TOKEN Bot token from @BotFather (required to enable Telegram)
TETHERLY_TELEGRAM_ALLOWED_USER_IDS Comma-separated user IDs (required)
TETHERLY_TELEGRAM_ALLOWED_CHAT_IDS Restrict commands to these chats

Shared

Variable Default Notes
TETHERLY_STATE_PATH ~/.tetherly/state.json Where bindings are persisted
TETHERLY_DEFAULT_TAIL_LINES 40 Default /tail line count
TETHERLY_MAX_TAIL_LINES 200 Cap for /tail
TETHERLY_LOG_LEVEL INFO Logger verbosity

A .env in the current working directory still overrides ~/.tetherly/.env. At least one of DISCORD_BOT_TOKEN or TELEGRAM_BOT_TOKEN must be set.

Agent CLI hooks

All hook handlers gate on the same flag: they only forward when the active tmux session has TETHERLY_NOTIFY_ON_FINISH=1. /bind sets it, /unbind clears it — projects without a binding stay silent even when global hooks are installed. None of the handlers return a blocking decision, so each CLI's normal prompts still appear in the terminal.

Codex

Installed via tetherly install-hooks (or globally during tetherly init).

  • Stoptetherly codex-stop forwards last_assistant_message to the bound chat.
  • PermissionRequesttetherly codex-permission-request forwards the tool/command/reason.

Claude Code

Installed via tetherly install-claude-hooks (or globally during tetherly init). Writes to ~/.claude/settings.json (global) or <project>/.claude/settings.json (project) — existing keys, other event entries, and other tools' commands are preserved.

  • Stoptetherly claude-stop forwards last_assistant_message. Skips when stop_hook_active=true so it doesn't double-fire if another hook is keeping Claude going.
  • Notificationtetherly claude-notification forwards the notification message. Routes permission_prompt notifications with the permission keyboard (Yes/No), other types as plain text.

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

tetherly-0.3.0.tar.gz (698.4 kB view details)

Uploaded Source

Built Distribution

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

tetherly-0.3.0-py3-none-any.whl (36.3 kB view details)

Uploaded Python 3

File details

Details for the file tetherly-0.3.0.tar.gz.

File metadata

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

File hashes

Hashes for tetherly-0.3.0.tar.gz
Algorithm Hash digest
SHA256 8a3146cae94554cbb71af1c8da8be8c3c31db93ff35b707180b437239c4c22de
MD5 0786df6e7d149bd919f417477f3ce36c
BLAKE2b-256 e57a365f463af69a1f40053e9bfcbfb641e76d39c1aa72ce9038e0ef8f9b1daf

See more details on using hashes here.

Provenance

The following attestation bundles were made for tetherly-0.3.0.tar.gz:

Publisher: publish.yml on changhyeon363/tetherly

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

File details

Details for the file tetherly-0.3.0-py3-none-any.whl.

File metadata

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

File hashes

Hashes for tetherly-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4154548c718fea1e7ab3f7604bcb0a61be2904d0a80eac949e5052706f9ac50d
MD5 7ba3659c0f630b7a57731408fee5a9d5
BLAKE2b-256 5acfd94ef9eeda5b973ad52b53aea845e6a0f8195feae4b9bf5531358aeedaec

See more details on using hashes here.

Provenance

The following attestation bundles were made for tetherly-0.3.0-py3-none-any.whl:

Publisher: publish.yml on changhyeon363/tetherly

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