Needs You
The inbox for the four things that stop being anybody's job if nobody looks.
Agents run unattended. When one of them cannot proceed without a person, the work stops and waits — it does not guess, and it does not carry on with a lowered standard. That is the right behaviour and it creates a new problem: something is now waiting, and nobody has been told. This page is the answer to what is waiting on me.
The four sections
| Section | What is in it |
|---|---|
| Approvals | Pending approvals this person may decide — not every pending approval |
| Blockers | Open blockers assigned to them, plus unassigned ones of high or critical severity |
| Failed or stale sessions | Sessions that failed, or went silent, on work that is still open |
| Rejected handoffs | Handoffs a destination runtime refused |
Three of those boundaries are deliberate and easy to get wrong in the other direction.
A stale session is listed, never failed. A session whose agent died cannot say so; Kernel
infers it from the silence — no heartbeat (or, if it never sent one, no start) inside
KERNEL_SESSION_STALE_AFTER_SECONDS, five minutes by default — and lists it here beside the
failures, still running. Stale is a fact about silence; failed is a claim about the work,
and only a person makes it: the session page offers Mark completed and Mark failed
(with a reason), and the record says who decided. Managed sessions are heartbeated by their
daemon; an attached one by kernel session heartbeat --every 30 & in the shell that
attached it (the CLI).
Approvals is "may decide", not "pending". An approval can name a required user or a required role, so whether it belongs in your inbox is a property of the pair, not of you. An inbox listing every pending approval would send people to a page that then refuses them.
Unassigned blockers appear only when they are severe. A low or medium blocker with no
owner is a note, and notes do not belong in an inbox — an inbox that fills with them stops
being read, which costs more than the notes are worth. High and critical are exactly the
severities that hold a work item in blocked, so an unowned one is work nobody has picked
up rather than a remark.
The badge
The navigation carries the total. It is fetched after the page paints, from its own route, rather than counted during every page render: four counting queries on every page in the application is a cost the reader never asked for. It refreshes on the same live-update hints the rest of the shell listens to.
The badge and the page are the same query. Both go through the services' count_* and
list_* methods — the methods the API's GET /organizations/{id}/needs-you calls, not the
same rules restated somewhere else. A count computed separately from its list agrees with
it until the first rule change and then disagrees silently, in the direction that sends
somebody to a page to find nothing there.
The counts come from the count_* methods rather than from the number of rows rendered: a
section shows at most fifty, and counting the rendered rows would under-report the moment
someone had more than fifty things waiting.
Keyboard
j and k move between rows, Enter opens the focused one, and a or r opens the
decide dialog for a focused approval.
These are a faster way to do what the keyboard already does, never the only way. Every row
is a link and every action is a button, so the page works with Tab and Enter alone
before a single shortcut is involved — which also means it works for someone whose
assistive technology has claimed j and k for itself.
An empty inbox
An empty inbox means the agents are unblocked. It does not mean nothing is happening, and the page says so rather than showing a blank panel that reads as broken.