<feed xmlns='http://www.w3.org/2005/Atom'>
<title>dingger.git/crates/dinggerd/assets/pi, branch master</title>
<subtitle>Watches the AI coding agents in your tmux panes on macOS and tells you which need you, from the menu bar, a floating panel, the status line and notifications; jumps to them, and restores tmux sessions and agents after a crash
</subtitle>
<id>https://git.soarez.net/sz/dingger.git/atom?h=master</id>
<link rel='self' href='https://git.soarez.net/sz/dingger.git/atom?h=master'/>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/dingger.git/'/>
<updated>2026-11-03T11:05:57+00:00</updated>
<entry>
<title>show each pi agent's context use: a meter in the panel and search, text in the menu</title>
<updated>2026-11-03T11:05:57+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-11-03T11:05:57+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/dingger.git/commit/?id=bd1eb9ef9b3b89ff5825eb8bf9b2e978167c9ad0'/>
<id>urn:sha1:bd1eb9ef9b3b89ff5825eb8bf9b2e978167c9ad0</id>
<content type='text'>
</content>
</entry>
<entry>
<title>mark forgotten drafts in pi agents' input boxes, and keep them across a crash or restore</title>
<updated>2026-10-30T16:59:43+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-10-30T16:59:43+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/dingger.git/commit/?id=959f0d46cac1a09d0821da599d8dff54d1147892'/>
<id>urn:sha1:959f0d46cac1a09d0821da599d8dff54d1147892</id>
<content type='text'>
</content>
</entry>
<entry>
<title>reload pi agents on an old extension: versioned extension, control socket, menu item and reload-agents</title>
<updated>2026-10-30T15:27:21+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-10-30T15:27:21+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/dingger.git/commit/?id=b0cfd10b80443d3f67d263ff4db177bb53cc90ed'/>
<id>urn:sha1:b0cfd10b80443d3f67d263ff4db177bb53cc90ed</id>
<content type='text'>
</content>
</entry>
<entry>
<title>pi: no footer line for the importance</title>
<updated>2026-10-27T12:25:44+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-10-27T12:25:44+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/dingger.git/commit/?id=a7e065cd4f39abda178af58127ead1ab502e0f3b'/>
<id>urn:sha1:a7e065cd4f39abda178af58127ead1ab502e0f3b</id>
<content type='text'>
it took a line of its own in pi's footer. pi says the level when it is
set, and /importance alone shows it; pi clears the old line at /reload.
</content>
</entry>
<entry>
<title>mark as unread: make an idle agent done again, to come back to it</title>
<updated>2026-10-27T12:12:28+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-10-27T12:12:28+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/dingger.git/commit/?id=50c433e82c368b9861a89deecb74e5f29fa50353'/>
<id>urn:sha1:50c433e82c368b9861a89deecb74e5f29fa50353</id>
<content type='text'>
like "mark as unread" in mail: an agent you have seen (idle) becomes done
again, last among done agents of its importance, with no sound or
notification. it stays done until you come back to it: leave its tmux
window and return, or jump to it. marked while you look at it, it holds
until you look away (`held`); a new turn clears it. only idle agents can
be marked.

- daemon: `pane.mark_unread` on the hook socket; the watcher applies it
  after the tick's observations (mark_unread, advance's hold rule).
- `dingger unread [--pane]`: refuses done, working, blocked, and panes
  without an agent; returns once the agent shows as done.
- pi: /unread (refused while the agent works or is blocked).
- panel: right-click an idle agent in the full list, "Mark as unread".
- search: ⌘U or right-click marks the selected idle agent; the footer
  offers ⌘U when it applies; search stays open.

tests: unit (hold, jump, new turn, idle only), e2e step 22 (queue
position, hold, look away and back, jump, refusals, no sound, menu, the
extension), pi-live in real pi 1.4 (a mark, not a turn: an unknown
command would also end done), swift selftest (menu only for idle, footer).
</content>
</entry>
<entry>
<title>importance: mark an agent high, normal, or low</title>
<updated>2026-10-26T14:32:18+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-10-26T14:32:18+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/dingger.git/commit/?id=185af91b4d525db6c192a050b53615772fb5fe11'/>
<id>urn:sha1:185af91b4d525db6c192a050b53615772fb5fe11</id>
<content type='text'>
within a status, more important agents are listed first, and so jumped to
first; status stays first. a high agent shows a bold ! before its name, a
low agent's name is lightly dimmed with "low" on its second line, and it
makes no sound (it still notifies and waits in line).

in pi, /importance high|normal|low (completes the levels; none once one is
typed out, so Enter runs it). the extension saves it in the session as a
custom entry (dingger-importance), so /reload, restarts, /resume and
restore bring it back; /new starts at normal. it shows a level other than
normal in pi's footer, emits dingger:importance { level } for other
extensions, and sends it with every report. for other agents, `dingger
importance [level] [--pane]`; it refuses a pi that reports itself, whose
saved level would win.

the daemon stays the one writer of pane state: it writes
@dingger_importance (unset for normal), which goes with the agent and
survives a daemon restart. `dingger status` marks high and low.

tests: e2e step 21 (order, the option, no sound for low, the menu bar,
the command, the extension through a harness that now matches pi's
extension API), a DINGGER_SOUND seam so sounds are observable, and a
status-line check that read the counts once (flaky) now polls.
pi-live: /importance in real pi 1.4, its footer and session entry, and the
level after a restore; every pi there now uses the test's agent directory
(a restored pi read the user's). negative controls fail each part.
</content>
</entry>
<entry>
<title>restore, step 2: resume agents, retype command lines</title>
<updated>2026-10-23T10:20:11+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-10-23T10:20:11+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/dingger.git/commit/?id=c082f5044eedd2294d72f920d1018e40d73aab33'/>
<id>urn:sha1:c082f5044eedd2294d72f920d1018e40d73aab33</id>
<content type='text'>
- the pi extension reports its session file; the daemon keeps it in the
  pane option @agent_session, and snapshots carry it. restore runs
  `pi --session &lt;file&gt;` in the rebuilt pane, one agent every 0.5s, then
  reports which agents run and which were interrupted mid-turn.
- other panes: the command line running in them is typed at the new
  prompt but not run. exactly as typed with the zsh hook (dingger install
  zsh: preexec/precmd keep @dingger_cmd), else the foreground program's
  exact argv from the kernel (KERN_PROCARGS2), shell-quoted.
- "at a prompt" is the pane's own shell owning the terminal's foreground
  process group, not a name check: `sh -c ...` is a running program.
- an agent or command that exits keeps its place in snapshots for 60s, so
  a shutdown that stops programs before tmux still restores them.
- typing waits for each new prompt (text typed earlier echoes twice).

e2e step 16 covers resume with a session path containing a space, the
interrupted report, an agent that exits just before the server dies, a
quoted command retyped not run, and the hook's text; dropping the grace
period, judging prompts by name, running retyped commands, or not storing
the session reference each fail it. the test's fake pi is guarded so a
real pi never starts.
</content>
</entry>
<entry>
<title>pi extension: identify the pane from TMUX_PANE</title>
<updated>2026-10-20T10:04:18+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-10-20T10:04:18+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/dingger.git/commit/?id=3731a80384f5e2b7d3343eb3e4999f626bbc7f91'/>
<id>urn:sha1:3731a80384f5e2b7d3343eb3e4999f626bbc7f91</id>
<content type='text'>
the extension asked tmux for "the current pane", which resolves to the
session's active pane, not the pane pi runs in, so agents in background
windows reported their state onto another pane. tmux sets TMUX_PANE for
every process it starts in a pane; use it.

e2e step 12 loads the shipped extension with a fake pi from a pane that
is not its session's active pane and asserts the report lands there; it
fails against the previous extension. hook reports log at info again.
</content>
</entry>
<entry>
<title>menu bar: herdr-style colored state glyphs; tmux segment before the clock</title>
<updated>2026-10-19T16:30:03+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-10-19T16:30:03+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/dingger.git/commit/?id=fed066bc3908d18ede5490130975203a56c48fc2'/>
<id>urn:sha1:fed066bc3908d18ede5490130975203a56c48fc2</id>
<content type='text'>
the design panel's monochrome template rendering made every row look
alike; restore herdr's agent-panel visual language - green ready, yellow
working, red blocked, filled when unseen in the queue. the tmux segment
moves left of the clock so it is visible at a glance; the status item
logs what it observes for diagnosis.
</content>
</entry>
</feed>
