A feature release, aimed at one loop: start an agent, look away, come back the
moment it needs you. Until now the panel could only help while you were looking
at it. This release makes it reach out when you are not, and makes answering a
keystroke instead of a context switch.
Added
Desktop notifications, on by default. When an agent starts waiting or
failed, you get a system notification even when Zellij is not the focused
window - which is exactly when a blocked agent is invisible. show_self only
raises a floating pane inside Zellij, so this is the case the panel
structurally could not cover.
The plugin decides rather than the hook, because only the plugin holds every
agent's state. That buys three things a per-hook notifier could not: a burst of
five blocked agents becomes one banner instead of five stacked ones, each agent
is rate-limited, and nothing fires while the panel is already on screen.
LaunchOrFocusPlugin "file:~/.config/zellij/plugins/zj-agent-mob.wasm" {
floating true
notify "waiting,failed,done" // add done; "" turns notifications off
notify_sound "true"
}| option | default | |
|---|---|---|
notify |
waiting,failed |
Which transitions notify. Any of waiting, idlewait, failed, done |
notify_cooldown |
60 |
Seconds before the same agent may notify again |
notify_sound |
false |
Play a sound with the notification |
The notifier is probed once (terminal-notifier → osascript → notify-send)
and cached. Finding none disables the feature silently, and the panel behaves
exactly as it did before.
Quick reply. y answers a blocked agent, m opens a
one-line editor - Enter sends, Esc cancels. Both are
restricted to agents that are actually blocked, because keystrokes sent to an
agent mid-turn land as stray input.
Fleet summary for status bars. Opt-in. Writes 2 waiting · 3 working on
every change and pipes it as zj-agent-mob-summary, so you can see whether
anyone needs you without opening anything:
summary_file "/tmp/zj-agent-mob-summary"zjstatus picks it up with its pipe widget;
anything else (a starship prompt, a shell script) can read the file.
Fleet ergonomics. D clears every done badge at once,
n opens a new agent in the selected row's directory, and a row blocked
for more than two minutes paints as an error so it stops blending into the list.
Changed
x, y and m now work across sessions. These
were previously refused for foreign rows, because the plugin's shims are
session-local - the old README told you to jump first. They are now routed
through zellij --session X action, verified against live sessions for all
three.
Urgent transitions skip the poll. Each open panel drops a beacon, and the
hook pipes waiting / failed / done straight to those sessions instead of
letting them wait for the next scan. Heartbeats keep the spool-only path, so the
hot path costs nothing extra. Set ZJ_AGENT_FANOUT=0 to opt out.
Fixed
Three wrong-target bugs, all found during review of this branch. Each is covered
by a test that fails without its fix.
Replies went to the cursor, not the agent they were composed for. Another
agent blocking mid-typing re-sorts the list, so the text would have landed in the
newly-selected agent's prompt.
The second x acted on the selection, not the arm. kill_armed
held an AgentId, but only ever used it as an equality test - so any pipe
arriving between the two presses could move the confirmation onto whatever had
taken the cursor. A failed row outranks everything in the sort and is itself
a fan-out trigger, which makes this routine rather than contrived.
Sessions were addressed by their sanitized name. AgentId.session is folded
to [a-zA-Z0-9._-] so it can key a spool filename, and that same string was
being passed to zellij --session. A session named my session keys as
my_session, which addresses nothing:
$ zellij --session my_session action write-chars "y"
Session 'my_session' not found. The following sessions are active:
...
$ echo $?
0The row was removed optimistically, so the kill appeared to succeed while the
agent kept running. Identity and addressing are now separate concerns: sanitized
for filenames, real_session() for anything taking --session. This also fixes
a pre-existing bug in the jump path on v0.3.1.
Two related fixes fell out of the above:
zellijexits 0 for a session that does not exist, reporting it on stderr
only. The failure handler checks both streams, or it would have missed exactly
the case it exists for. Failures now render under the list instead of the row
silently vanishing.- Waiting-escalation never fired locally.
arm_timeronly ticked for active
or foreign rows, so a blocked local agent - the single-session case the
feature is for - froze the clock and never reached its threshold.
Upgrading
No configuration changes are required; notifications turn themselves on, and
everything else is opt-in. Restart your agents after upgrading so they pick up
the new hook script.
curl -fsSL https://github.com/mohseenrm/zj-agent-mob/releases/download/v0.4.0/init.sh | shRequires jq. See the README
for the manual path and configuration.