Что там делают мои AI-агенты: tmux-agent-indicator

19 April 2026

Обычный день: пять агентов работают одновременно. Claude Code рефакторит модуль в одной панели. Codex подкручивает тесты в другой. OpenCode в третьей. А где-то в окне tmux номер 4 агент уже пять минут как закончил и ждёт, пока я это замечу.

Вот ровно из-за последнего и появился этот пост.

Тихая проблема CLI-агентов

CLI-агенты расплодились. Claude Code, Codex, OpenCode, Aider, Cursor в режиме терминала, свои питон-скрипты поверх API. Разработчики, которые ещё год назад не открывали терминал, теперь в нём живут. И почти каждый запускает больше одного агента одновременно — задачи параллелятся: здесь сгенерить миграцию, там набросать README, в третьем месте гонять флакающий тест.

Проблема становится очевидной за неделю: ты теряешь контроль.

Какой агент сейчас думает? Какому нужно дать разрешение на выполнение команды? Какой закончил десять минут назад и просто мигает курсором, которого никто не видит? Никакого общего статус-бара для агентов нет. Узнать можно только одним способом — переключиться в каждую панель.

Ренессанс терминала

За последние пару лет произошло тихое: терминал снова стал модным. tmux в частности всё чаще всплывает в сетапах и скриншотах там, где пять лет назад был бы IDE. Часть причины — эстетика. Большая часть — в том, что AI-агенты прилетают в терминал первыми. Claude Code — это CLI. Codex — это CLI. Почти вся агентская UX сейчас — это текст, льющийся в pty.

tmux под это ложится идеально. Одно окно на проект, панели под агента и логи и свободный шелл, сессии для переключения между клиентами. Терминал перестал быть местом исключительно для ls и vim.

Но у tmux нет нативного понятия «в этой панели агент, которому ты нужен».

Что я хотел

Сигнал, который говорит мне без переключения панелей:

  • где сейчас работает агент
  • где агент ждёт ввода (разрешение, уточнение, блокирующий вопрос)
  • где агент закончил и ждёт

И чтобы это было пассивно. Без всплывающих окон, ворующих фокус. Без звуков, срабатывающих посреди встречи. Просто изменение того, на что я и так смотрю: статус-бар, рамка панели, заголовок окна.

Среди готовых плагинов tmux полно часов, CPU, git-веток и погоды. Агентов не трекает никто.

Пришлось написать.

tmux-agent-indicator

accessd/tmux-agent-indicator — плагин для tmux, отслеживающий три состояния на панель: running, needs-input, done. Каждое состояние управляет четырьмя визуальными каналами:

  • цвет рамки панели
  • фон панели (по умолчанию выключен, чтобы не бил по глазам)
  • фон и цвет заголовка окна
  • иконка в статус-баре, отдельная на агента (claude=🤖, codex=🧠, opencode=💻)

Короткое видео того, как это работает. Панель завершается, заголовок окна меняется, рамка обновляется. Если я фокусирую панель, состояние сбрасывается само.

Три кадра-примера:

needs-input done done-pane-bg
needs-input: жёлтый заголовок окна done: красный заголовок окна done: смена фона панели

Как состояние вообще попадает внутрь

Плагин ничего не поллит. Переходы состояний идут через хуки:

  • Claude Code стреляет хуки UserPromptSubmit, PermissionRequest, Stop. Инсталлер прописывает их в ~/.claude/settings.json.
  • У Codex есть команда notify в ~/.codex/config.toml, плагин вешается туда.
  • OpenCode имеет систему JS-плагинов. Инсталлер кладёт файл в ~/.config/opencode/plugins/.
  • Любой другой агент может звать scripts/agent-state.sh --agent <name> --state <state> из своего хука или враппера.

Для агентов, у которых хуков нет вообще, есть фолбэк через детект процессов: плагин смотрит настроенные имена процессов (claude, codex, aider, cursor, opencode) и помечает панель как running, когда они запущены.

Отложенный сброс

Одна маленькая деталь, которой я особенно дорожу. Когда панель переходит в done, визуальное состояние не чистится в момент хука. Оно чистится, когда ты реально посмотришь на панель (переведёшь фокус). Иначе done — это призрак, который мигает и пропадает до того, как ты его заметил, а смысл был ровно в обратном.

Session dots

Если у тебя больше трёх-четырёх сессий, есть опциональный индикатор сессий в статус-баре. Каждая сессия — точка. Текущая заполнена. Сессии, где агент просит внимания, подсвечиваются другим цветом. Четыре сессии, вторая активна, четвёртая требует внимания — выглядит как ○●○●.

Установка

curl -fsSL https://raw.githubusercontent.com/accessd/tmux-agent-indicator/main/install.sh | bash

Инсталлер предложит интерактивный визард по цветам, его можно перезапустить потом. И автоматически пропишет интеграции с Claude, Codex и OpenCode, если они установлены. Если предпочитаешь TPM:

set -g @plugin 'accessd/tmux-agent-indicator'

И добавь #{agent_indicator} (и при желании #{agent_session_dots}) в status-right.

За пределами tmux: agent-indicator

tmux-agent-indicator — плагин исключительно под tmux. Полезен тем, кто живёт в tmux, бесполезен остальным.

Мне хотелось тот же сигнал о состоянии и в других поверхностях: обычные табы терминала, системные уведомления, звуки, push на телефон. Так появился отдельный проект — accessd/agent-indicator.

Та же модель хуков, те же три состояния, четыре бэкенда:

  • Terminal. Ставит заголовок таба через OSC 2, тонирует фон через OSC 11, дёргает bell на needs-input, а на iTerm2 просит внимания в доке через OSC 1337;RequestAttention. Работает и внутри tmux, и снаружи — последовательности оборачиваются в tmux passthrough, когда надо. Проверено на iTerm2, WezTerm, Kitty, Ghostty, Alacritty, Windows Terminal, GNOME/VTE.
  • Sound. Играет звуковые алерты на needs-input и done. Использует звуковые паки формата CESP с no-repeat-логикой, чтобы один и тот же динь не звучал подряд. Фолбэк по плееру: afplay, paplay, aplay, play.
  • Desktop. Системные попапы, отдельно от уровня терминала. На macOS — terminal-notifier или osascript. На Linux/WSL — notify-send.
  • Push. HTTP-уведомления на телефон через ntfy, Pushover или Telegram. Вот этот бэкенд даёт отойти от ноутбука и всё равно знать, что агент ждёт.

Все четыре независимы и тогглятся по отдельности. По умолчанию после установки включён только terminal, остальные выключены. Визард проводит через каждый бэкенд.

Установка:

bash <(curl -fsSL https://raw.githubusercontent.com/accessd/agent-indicator/main/install.sh)

Конфиг живёт в ~/.config/agent-indicator/config.json. У каждого бэкенда свой dotpath и config.py, который читает и пишет значения.

Почему два проекта, а не один

Потому что tmux-специфичные штуки (рамки панелей, стили заголовка окна, анимация Knight Rider, session dots, семантика reset-on-focus) не имеют никакого отношения к звуку и push, а тянуть tmux как зависимость на пользователей без tmux — неправильно. Живёшь в tmux — бери плагин. Нужны звук и push, а стили tmux неинтересны — бери agent-indicator. Нужно и то и то — запускай бок о бок, у них общий хук-контракт.

Итог

Ренессанс терминала — не про ностальгию. Он про то, что самый быстрый и компонуемый интерфейс для нового поколения AI-инструментов оказался тем же, что у нас уже был. tmux даёт структуру, хуки дают расширяемость, агенты дают рычаг.

Не хватало простого: способа понимать, что делают твои агенты, не глядя на каждого из них. Два проекта закрывают этот пробел для меня. Если закроют и для тебя — звёзды приятны, PR-ы ещё приятнее.