v0.3.0
Agents in other Zellij sessions now report live status.
Before this release the panel found agents everywhere and could jump to them, but only agents in your current session reported what they were doing. Everything else sat at found and decayed to unknown after 60 seconds. That undercut the whole point of the panel: "who is blocked waiting on you" only held inside one session.
Now every agent reports live status, across every session — including sessions with no attached client, which Zellij's SessionUpdate structurally cannot see.
zj-agent-mob 1 waiting · 2 working · 1 done
▶ 1 ● codex waiting 2s web Fix flaky checkout test
└ needs approval: rm -rf node_modules · pane:5
2 ⠙ claude working 14s api Add retry to webhook client
└ Edit src/webhook.rs · 2 turns · pane:9
Rows 1 and 2 can now be in three different sessions and all stay live.
How it works
The hook writes one small record per agent to $TMPDIR/zj-agent-mob-<uid>/status/<session>.<pane_id>, and the panel reads that directory on the same command that already runs its process scan — so polling still costs one command, not two.
The write is a printf plus an atomic rename(2). No subprocess, nothing to block on. That matters because this runs on the critical path of every tool call.
Two designs were considered and rejected:
| Approach | Why not |
|---|---|
| Hook pipes to every session | N subprocess spawns per tool event, on the turn's critical path |
| A designated hub session | zellij --session X pipe blocks when the hub has no panel open — stalls every agent on the machine |
The rule that makes it safe
A spool record never creates a row. Existence comes from the process scan; the spool only refines a row the scan already justified.
So a leftover file cannot resurrect an agent that exited, and losing or clearing the spool degrades to the previous behaviour rather than breaking anything. Four defences keep a stale record from showing wrong data:
| Defense | Stops |
|---|---|
| No process, no row | A record for an agent that has exited |
session_id must match |
A recycled pane id inheriting the previous agent's status |
ts past the stale threshold ignored on read |
A record from a previous boot or a long-idle agent |
| Filename must match the record's own session/pane | A malformed or mislabelled file |
Records are dated relative to the newest one seen rather than against a wall clock the plugin does not have, so a host clock jump cannot pin a row as permanently current.
Upgrading
curl -fsSL https://github.com/mohseenrm/zj-agent-mob/releases/download/v0.3.0/init.sh | shImportant
Restart your claude / codex sessions. Hooks are read at session start, so an agent still running with the old hook writes no record and will keep showing found from other sessions. This is the one manual step.
No configuration changes are needed. Existing keybindings and layouts keep working.
Privacy and opting out
Records contain task summaries, which are your own prompts. The spool directory is created 0700 and namespaced by uid, so on a shared /tmp another user cannot read it.
To turn the cross-session transport off entirely, set ZJ_AGENT_SPOOL=0 in the agent's environment. Status for the agent's own session keeps working through the existing pipe.
| Variable | Default | Meaning |
|---|---|---|
ZJ_AGENT_SPOOL |
1 |
Set 0 to stop writing status records |
ZJ_AGENT_SPOOL_DIR |
$TMPDIR/zj-agent-mob-<uid>/status |
Where records are written |
Also in this release
- Hardening:
ZELLIJ_PANE_IDreached a file path unsanitized while session names were already folded. Found by adversarial testing; now rejected unless numeric. No shell execution was possible either way. - Docs:
how-it-works.mdgains Cross-session status: the spool and a Who owns which row section;troubleshooting.mdgains a step-by-step guide for a row stuck onfound. - The README's "no daemon, socket, or state file" is now "no daemon and no socket" — the spool is a state file, and quietly dropping the claim would have been worse than correcting it.
Verification
174 unit tests (up from 148), 113 hook end-to-end cases (up from 85), and 98 installer cases.
Two tests drive the whole loop rather than one layer: one runs the real hook script, the real scan script, and the real merge in sequence; the other replays bytes captured from two live Zellij 0.44.3 sessions.
Full Changelog: v0.2.0...v0.3.0