I wanted agent state in Zellij, not another tab I forget about

I run coding agents inside Zellij under Ghostty. Claude, Codex, Grok, Pi, whatever is useful that week. Several tabs. A few floating panes. The agent that needs a permission prompt never feels urgent until I happen to look at the right surface.

You know the loop. Switch tab. Read the bottom of a scrollback. Switch again. Miss the one that finished twenty minutes ago. Desktop is quiet because nothing ever told it the state changed. The multiplexer is great at panes. It is not great at "which agent is stuck on allow?"

I did not want another orchestration layer. I did not want a fork of Zellij just for a status rail. Stock 0.44.3+ was the bar. Two WASM plugins and a pure Rust core felt like the right size.

The product itch came from Herdr and its agent panes: real terminals, agent state rolled up so you can jump to blocked work instead of polling every surface by hand. Herdr is an agent multiplexer. I live in Zellij already. The design question was how much of that agent-pane idea can sit on stock Zellij as plugins, without replacing the multiplexer.

So I shipped zj-agents.

What it is for

zj-agents is semantic state for coding-agent panes on unmodified Zellij. A background engine discovers panes that look like known agents, classifies what the viewport is saying, and pushes a small snapshot. A sidebar renders that list, focuses a pane when you hit Enter, and stays hideable so it is not another permanent column.

States matter more than pretty glyphs. Unknown. Idle. Working. Blocked. Done. Blocked means a real rule matched something like a permission prompt, not a random fallback. Done is derived: two successful Idle observations after Working while the pane is unfocused. Focus clears sticky Done without a notification spam loop. That table lives in pure code so tests can hammer it without a host.

Desktop notifications exist, but only on new Blocked and Done transitions when the pane is not focused. Labels go through a sanitizer first. Hostile titles and markup do not get to train your notification daemon.

What problem that actually closes

The desk problem is attention, not another chat UI. I already have agents. I already have panes. I needed a shared, boring truth:

  • which pane is an agent
  • what state it is in
  • whether I should look now
  • without pasting full screen contents into a second process that logs everything

The engine is the only thing allowed to read viewports. The sidebar only sees sanitized metadata and derived state over a versioned pipe (hello, snapshot, reload). No bye, no ack theater. Privacy was a product requirement, not a footnote.

Install is the usual Zellij story. No package manager. Release WASM, named aliases in config, load_plugins for the engine. v0.1.0 is up with both artifacts and checksums. From the repo: nu scripts/install.nu --from-release, or curl the assets into ~/.config/zellij/plugins/.

Where it came from

Primary inspiration: Herdr's agent pane model. Semantic state on real PTYs (blocked, working, done, idle), see the herd at a glance, jump to what needs you. Herdr owns that stack as a multiplexer. I wanted the awareness layer without leaving Zellij.

On the Zellij shelf I also checked awesome-zellij. zj-radar is the closest cousin (sidebar of agent states; more push/pipe). zellaude goes deep on Claude in the status bar. zellij-attention puts icons on tab names from hooks. Different shapes.

So the pitch is not "nobody did agent awareness." It is Herdr-shaped state on stock Zellij: fixture-backed manifests, engine plus hideable sidebar, no fork, no required hooks. Listing PR on awesome-zellij for that reason.

How it got built

This one did not start as a blank weekend doodle. There was a design pass and a long implementation plan (semantic state, inventory bootstrap, atomic manifest reload, notification coalescing). Codex work handed off into a Grok-driven session under subagent-driven development: task, implement, review, fix until the bar held.

The same desk rules as other recent ships. No green CI that still ships stubs. No production warning suppressions as a lifestyle. Fixtures for Claude, Codex, Grok, Pi, and OMP before claiming detection. Patterns come from redacted captures, not README poetry. That slowed the agent list. It also kept OpenCode and friends out until someone brings real viewports.

Upstream style hygiene followed the same pattern as Keylore and tessera: dual license, Dependabot, verify on Ubuntu and macOS, release on v* tags with git-cliff notes, branch rules that force linear history. Actions burned private minutes until the repo went public. Then the release job actually produced the WASM files the README pretends exist.

What is done, what is not

Done: core state machine and protocol, five bundled agents with fixture gates, engine session model, sidebar, install from release, public repo, v0.1.0 assets.

Not done: I am not claiming a full interactive smoke matrix on every host. Zellij still needs permission grants once. Classification is only as good as the fixtures and rules. If your agent UI changes, manifests change. That is the product.

If you live in multi-agent Zellij sessions and keep missing the pane that is waiting on you, that is the itch. Clone or curl. Grant the batches. Open the sidebar. See if the desk gets quieter.

Tools