Skip to content

v0.3.0

Choose a tag to compare

@github-actions github-actions released this 09 Aug 18:56
· 5 commits to main since this release

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 | sh

Important

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_ID reached 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.md gains Cross-session status: the spool and a Who owns which row section; troubleshooting.md gains a step-by-step guide for a row stuck on found.
  • 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