Telegram-native · Zero dependencies

yeci-notify

A remote control for your AI coding agents

yeci-notify pushes approvals and task updates from Claude Code, Codex, and Gemini CLI straight to your phone.

$ curl -fsSL https://notify.yeci.org/install.sh | bash

Installs a single binary to ~/.local/bin. Nothing runs and nothing is configured until you activate it.

Core Features

Notify

Get pinged the instant an agent needs a permission or finishes a task — foreground, tmux, nohup, or over SSH.

Approve

The terminal dialog, mirrored one-to-one: Allow, Deny, Deny with a note — plus the agent's own "always allow / don't ask again" options rendered as buttons.

Answer questions

When Claude asks a multiple-choice question, the options arrive as buttons. Tap one, or reply with your own answer — the "something else" path, remotely.

Presence-aware

Knows when you're at the terminal (tmux client activity / tty idle). Approvals pop locally while you're there, and go to your phone only when you're away.

Remote steer

Inject instructions into a live session from your phone — reply to any session notification, or use /send. Needs tmux; degrades gracefully to notify-only.

Multi-agent

Claude Code, Codex, and Gemini CLI unified behind one adapter layer, with defensive parsing across versions.

Single binary

One static CGO-free executable, no runtime dependencies. Present but absent until you run init — no processes, no config changes.

Secure by design

Outbound long-polling only — no public port or webhook. A single allowlisted Telegram ID; the token never touches logs or messages.

Agents & Platforms

Claude Code Codex Gemini CLI Telegram Linux macOS amd64 · arm64 systemd launchd tmux

Install

The install script detects your OS and architecture and drops one static binary into ~/.local/bin. Linux and macOS, amd64 and arm64.

# One-line install
curl -fsSL https://notify.yeci.org/install.sh | bash

# Custom install directory
YECI_BIN_DIR=/usr/local/bin curl -fsSL https://notify.yeci.org/install.sh | bash

Four static CGO_ENABLED=0 binaries per release, verified against checksums.txt.

Quick start

yeci-notify currently delivers notifications and interactive approvals through a Telegram bot only. Additional channels are on the roadmap.

One command activates everything. It is fully idempotent — re-run it any time to update.

yeci-notify init
  1. 1 Validate your Telegram Bot Token (from @BotFather) and capture your telegram_id (from @GotIDBot).
  2. 2 Detect installed agents and wire up their hooks — deep-merged, never overwriting your existing config.
  3. 3 Pick a launcher: systemd / launchd / shell lazy-start / manual, based on your environment.
  4. 4 Send a test notification to confirm the loop.

yeci-notify remove returns everything to factory state and restores every file it touched.

Telegram Bot Commands

/lsList sessions and each one's most recent event
/send <text>Inject text into the only active tmux session (lists candidates when there are several)
/send <session> <text>Inject text into a specific tmux pane
/pendingList pending approvals and re-render their buttons
/mute · /unmuteTemporarily silence notifications (approvals unaffected)
/statusRuntime status summary

Replying to a message works too: reply to an approval = deny with a note · reply to a question = your own answer · reply to a session notification = inject into that session.

Presence detection

Every approval is routed by where you actually are, judged from your latest keyboard activity (tmux client activity per session, or tty idle time outside tmux). Fully automatic — no toggling.

At the terminal

Input within the last 3 minutes

Dialog pops in the terminal instantly. Your phone stays silent.

Nearby

tmux attached, but no recent input

Pushed to Telegram with a short 30s wait, then falls back to the terminal.

Away

Detached / SSH dropped / no signal

Full remote approval flow on your phone.

Just tapped a button in Telegram? You're treated as remote even if the terminal saw recent input. Configurable via [presence] in config.toml; any probe failure safely defaults to "away".

Capabilities

The product mainline (top three rows) holds unconditionally, for every user and every way of running an agent. tmux is only an optional enhancement.

Feature Requires Without it
Done / idle / error notificationsAlways available
Claude / Gemini approval loop (all permission dialogs)Always available
Claude "always allow / don't ask again" options as buttonsAlways available
Claude questions (AskUserQuestion) answered remotelyAlways available
Codex done / approval notificationAlways available
Codex approval remote decisiontmuxNotify-only; decide at the terminal
Presence detectiontmux for best accuracyFalls back to tty idle time
/send / reply session injectiontmux"Session not injectable"
/ls session listtmuxLists sessions seen in the event stream

Security

config.toml is forced to 0600. The token supports ${ENV_VAR} expansion, so it need never hit disk.

The token never appears in hook configs, logs, Telegram messages, or any distributed artifact.

A single Telegram ID allowlist is a hard check — non-matching updates are dropped and never answered.

Outbound long-polling only. No public port, webhook, or HTTPS certificate required.

Dangerous commands render a reject-only prompt by default — high-risk actions keep the friction of returning to the terminal.

Your bot token is a remote for your dev machine. Guard it accordingly; after remove, revoke it via @BotFather.