---
title: Quiet chip (the "16m" clock badge on a session row)
---

# Quiet chip (the "16m" clock badge on a session row)

## What it is

A small grey **clock icon + duration** — `16m`, `45m`, `2h` — that appears on the right-hand end of a
session row in the left sidebar (and on the equivalent mobile row). It means exactly one thing:

> **This session is running, but it has produced no output for that long.**

It is a **silence timer**, not an error and not a progress bar. A session that is genuinely working —
thinking for a long time, waiting on a slow tool, running a big test suite — will wear the chip and be
perfectly healthy. That is the point: the chip makes long silence *visible* so you can decide whether to
look, without claiming anything is wrong.

Hovering the row shows **"No output for a while"** among the row's other indicator meanings; the chip's
own label reads **"Quiet for 16m — no output"**.

## Where to find it

Look at the left sidebar: the chip sits at the right-hand end of a session row, and the same badge appears on the equivalent row on a phone. There is no menu or setting for it. It appears on its own after fifteen minutes of silence on a running session, and disappears the moment the session speaks again.

Hovering anywhere on the row explains it together with the row's other small badges; the chip's own label reads "Quiet for 16m — no output".

## How it behaves

### When it appears (and when it does not)

- **Only on `running` or `starting` sessions** — the two statuses that can still emit output. A session
  that is paused, archived, errored, waiting on you, or finished never shows it, however old it is.
  (This deliberately mirrors the backend's own gate in `getSilentActiveSessionIds`, and is deliberately
  narrower than the shared `LIVE_STATUSES` set, which answers a different question — "does this session
  have a live process at all" — and would wrongly include `needs_you` / `waiting` / `error`.)
- **After 15 minutes of silence.** Below the threshold the row shows nothing extra, so a healthy busy
  sidebar stays uncluttered.
- **It updates itself on a 30-second tick.** Nothing in the app ever announces "fifteen minutes of
  silence have now passed" — silence is the absence of events — so a timer is the only thing that can
  notice the crossing. The chip appears on its own while you are looking at the list, with no click,
  refresh, or new message needed.
- **It disappears the moment the session speaks again**, because the timer is measured from the
  session's `lastActiveAt` — and every output event refreshes that field live, without waiting for a
  refresh of the session list (see "Why the chip used to lie" below).

A future timestamp (from clock skew) or an unparseable one reads as **not quiet** — never as a negative
or `NaN` duration.

### What it is NOT

- **Not an alert.** It is styled with muted `surface` tokens on purpose and is never given the amber
  "Needs You" or red error treatment. Nothing is asking for your attention.
- **Not the thing that rescues a stuck session.** A separate main-process sweeper
  (`session-silence-backstop-service.ts`) is what actually acts on a genuinely stranded session. The chip
  is purely informational and takes no action.
- **Not "the session is broken."** Long silence is normal for long tool calls and deep thinking.

### Reading it next to the other row badges

A session row can carry several small indicators; the quiet chip renders immediately after the waiting
badge. Common neighbours:

| Badge | Meaning |
| --- | --- |
| Clock + `16m` (grey) | **Quiet chip** — running, but silent for 16 minutes |
| `>_` terminal glyph | This session triggered N action(s) via the CLI |
| Hourglass / waiting badge | Parked waiting for a test slot |
| Coloured status dot | Running (green) · Needs You (amber) · Error (red) · Waiting (ember orange) |

Hovering the **row** explains all of them at once — that is the designed surface, rather than expecting
you to hover each 12-px icon. (See the "known rough edge" below.)

### Known rough edge — the ⋮ button overlaps the chip

The hover-revealed **⋮ "More actions"** button is positioned over the row's right edge, which is exactly
where the quiet chip sits. On a row that renders a trailing chip the row now reserves clearance so the
chip stays hoverable; on rows without one the ⋮ still floats over the right edge, which is what keeps
session names from being truncated ~30 px early (see
`session-sidebar-title-truncation-too-early-postmortem.md`). Either way, **hovering anywhere on the row**
gives you the full explanation.

### Why the chip used to lie (fixed 2026-09-03)

Between 2026-09-01 and 2026-09-03 the chip showed a number that was simply **wrong**: sessions that were
emitting output continuously wore `24m`, `35m`, `51m` chips that only ever climbed. Opening one of those
sessions showed `6s since last response` at the bottom of the conversation — the two readouts on screen
at the same time disagreed by 25 minutes.

The chip was measuring the right field; nothing was **updating** it. The renderer learned `lastActiveAt`
from exactly two places — a full session-list fetch, and a status-change push (which sets it to the
moment the status changed). Neither fires while a session simply keeps running. So a session that went
`running` and stayed `running` carried a `lastActiveAt` frozen at the start of its turn, and the chip
faithfully rendered **how long the current turn had been going** under the label "no output". The
detail-pane timer disagreed because it anchors on the conversation's own message rows instead, and the
database agreed with the detail pane — `last_active_at` for those same rows was under a minute old,
which is what proved the staleness was in the UI and not in the data.

The fix mirrors, in the renderer, the bump the database already does: every `SESSION_OUTPUT` event
advances the row's `lastActiveAt`. Two details make it honest and cheap:

- **It anchors on arrival time, not the event's own timestamp.** A streaming checkpoint deliberately
  reuses the turn's start time as its timestamp for the whole turn, so trusting that field would have
  bumped nothing. Receiving an event *is* the proof of activity.
- **It rewrites the row at most once a minute.** The chip ticks at 30 s against a 15-minute threshold, so
  the bump is throttled rather than fired on every token — otherwise a fast stream would rebuild the
  session list on every delta, which is the churn the streaming batch exists to prevent.

`lastActiveAt` is not a sidebar sort key (`compareRegularSessions` orders on status, the two message
timestamps, drag order, and start time), so keeping it fresh cannot reorder the list.

**Why the timer lives on the row, not on the chip.** The row is memoised, and a quiet session by
definition pushes no updates — so if only the chip watched the clock, only the chip would learn, and the
row's hover tooltip would sit frozen on "not quiet" for the whole quiet spell. That was a real bug: a row
grew a `16m` chip whose meaning the tooltip never mentioned. `useSessionQuiet` now runs on the row and
stores a **boolean**, so React skips the re-render on every tick except the one that flips it — the row
re-renders once, when the chip appears, and a status that can never go quiet arms no timer at all.
_(Fixed 2026-09-02 after a user asked what the "16m" meant and found the tooltip empty.)_

_Shipped 2026-09-01._

## For agents

### Where it lives in the code

- Component + hook: [SessionQuietBadge.tsx](../../src/renderer/src/features/dashboard/SessionQuietBadge.tsx)
  — exports `isSessionQuiet()` (the pure 15-minute predicate), `formatQuietDuration()`, the
  `useSessionQuiet()` hook that owns the tick, and the `SessionQuietBadge` chip that renders the number.
- Mounted by [SidebarSessionRow.tsx](../../src/renderer/src/features/dashboard/SidebarSessionRow.tsx)
  and [MobileSessionRow.tsx](../../src/renderer/src/features/dashboard/MobileSessionRow.tsx).
- The row's hover text is assembled in
  [session-indicator-tooltips.ts](../../src/renderer/src/features/dashboard/session-indicator-tooltips.ts).
- Tests: [session-quiet-badge.test.tsx](../../tests/unit/features/dashboard/session-quiet-badge.test.tsx)
  and [SidebarSessionRow.test.tsx](../../tests/unit/components/SidebarSessionRow.test.tsx).

## Related

No sibling page is linked from this one, so the library map is the way on: [INDEX.md](INDEX.md) lists every page and area, including the session-status and sidebar pages that sit beside this badge.
