Problem
When an agent or build is chewing through memory, there's no way to see it from inside Clawterm — the per-pane footer shows branch, Claude context %, vim mode, elapsed time, but no RSS. Users only notice when macOS swap pressure kicks in or Activity Monitor is open. For long-running Claude sessions in particular, knowing whether a pane is sitting at 200 MB or 2 GB is useful signal both for spotting runaway memory and for deciding when to /compact.
Proposed UI
A new small badge in the per-pane footer alongside the existing branch / ahead counter / elapsed time row. Format mirrors htop — 156M, 1.2G, 42M — with the unit suffix chosen by magnitude (KB/MB/GB). Color tokens use the existing --text-tertiary for normal, possibly stepping up to --warn / --crit past configurable thresholds (e.g. 1 GB warn, 4 GB crit), reusing the Claude context bar's ok/warn/crit thresholds pattern.
Placement: between the branch badge and the elapsed counter, inside the existing footer row built in src/pane.ts:746-757 (updateFooter()). Add resident_size to the structuralKey (line 737) so the cached render re-runs when the value buckets to a new display string.
Open: whether the badge counts only the foreground PID's RSS, or sums the whole foreground process tree (shell + agent + every subshell). The tree is more accurate for "what's this pane costing me" but is also more work — see Open questions below.
Backend implementation
Extend the existing batched poll_pane_info IPC in src-tauri/src/process_info.rs:29-97. No new command needed.
- Add a new field to
PanePollResult (lines 12-25): resident_size: Option<u64> (bytes; None if the syscall fails — keep the existing tolerant pattern).
- Use
proc_pidinfo(pid, PROC_PIDTASKINFO, ...) (flavor 4) — same syscall family as get_process_cwd_full already uses. Returns proc_taskinfo.pti_resident_size in bytes.
- Query the foreground PID (the
fg_pid parameter poll_pane_info already accepts), not the shell, so the badge reflects the active workload rather than zsh idling.
- Frontend: pull the value into
PaneState (src/tab-state.ts), bucket-quantize for display (round to 2 sig figs to avoid every-poll churn), render in pane.updateFooter().
Open questions
- Process tree vs foreground-only. Foreground-only is one extra syscall in the existing batched call. Tree-sum requires walking children (no native "process tree RSS" on macOS), which means iterating
proc_listpids(PROC_PPID_ONLY, parent_pid) per descendant and summing — cheap for a 3-pid tree, less cheap for a node project that spawns 50 subshells. Suggest: ship foreground-only first, add an opt-in pane.memoryIncludeChildren: bool config if anyone asks for it.
- Refresh cost. Already piggybacking on
poll_pane_info, so no new IPC frequency to worry about. pti_resident_size is read from kernel state with no I/O — well under 1ms per pane.
- Display unit threshold. 1024-based (
KiB/MiB/GiB) or 1000-based (KB/MB/GB)? htop/Activity Monitor differ. Suggest 1024-based to match macOS Memory column convention.
- Idle suppression. Current poll loop already throttles to
skipExpensive=true after 5 consecutive idle polls (src/tab.ts:794). RSS query is cheap enough to keep firing even when idle — a pane sitting on 4 GB while idle is exactly when you want to see it. Don't gate this behind skipExpensive.
Risks
Minimal. Reuses existing polling infrastructure and syscall pattern. The Option-based return lets a proc_pidinfo failure degrade gracefully — pane just doesn't show the badge.
Out of scope
- VSZ (virtual size) — almost never useful, would just confuse users.
- Per-pane CPU% — separate signal, file separately if anyone asks.
- Mac-only at this stage; ClawTerm has been macOS-only since v1.4.3, so no cross-platform syscall abstraction needed.
References
- Current footer rendering:
src/pane.ts:728-758 (updateFooter)
- Polling cycle:
src/tab.ts:768-880 (pollPane)
- Backend batched IPC:
src-tauri/src/process_info.rs:29-97
- Existing
proc_pidinfo usage: src-tauri/src/process_info.rs:171 (get_process_cwd_full)
Problem
When an agent or build is chewing through memory, there's no way to see it from inside Clawterm — the per-pane footer shows branch, Claude context %, vim mode, elapsed time, but no RSS. Users only notice when macOS swap pressure kicks in or Activity Monitor is open. For long-running Claude sessions in particular, knowing whether a pane is sitting at 200 MB or 2 GB is useful signal both for spotting runaway memory and for deciding when to
/compact.Proposed UI
A new small badge in the per-pane footer alongside the existing branch / ahead counter / elapsed time row. Format mirrors
htop—156M,1.2G,42M— with the unit suffix chosen by magnitude (KB/MB/GB). Color tokens use the existing--text-tertiaryfor normal, possibly stepping up to--warn/--critpast configurable thresholds (e.g. 1 GB warn, 4 GB crit), reusing the Claude context bar's ok/warn/crit thresholds pattern.Placement: between the branch badge and the elapsed counter, inside the existing footer row built in
src/pane.ts:746-757(updateFooter()). Addresident_sizeto thestructuralKey(line 737) so the cached render re-runs when the value buckets to a new display string.Open: whether the badge counts only the foreground PID's RSS, or sums the whole foreground process tree (shell + agent + every subshell). The tree is more accurate for "what's this pane costing me" but is also more work — see Open questions below.
Backend implementation
Extend the existing batched
poll_pane_infoIPC insrc-tauri/src/process_info.rs:29-97. No new command needed.PanePollResult(lines 12-25):resident_size: Option<u64>(bytes;Noneif the syscall fails — keep the existing tolerant pattern).proc_pidinfo(pid, PROC_PIDTASKINFO, ...)(flavor 4) — same syscall family asget_process_cwd_fullalready uses. Returnsproc_taskinfo.pti_resident_sizein bytes.fg_pidparameterpoll_pane_infoalready accepts), not the shell, so the badge reflects the active workload rather than zsh idling.PaneState(src/tab-state.ts), bucket-quantize for display (round to 2 sig figs to avoid every-poll churn), render inpane.updateFooter().Open questions
proc_listpids(PROC_PPID_ONLY, parent_pid)per descendant and summing — cheap for a 3-pid tree, less cheap for a node project that spawns 50 subshells. Suggest: ship foreground-only first, add an opt-inpane.memoryIncludeChildren: boolconfig if anyone asks for it.poll_pane_info, so no new IPC frequency to worry about.pti_resident_sizeis read from kernel state with no I/O — well under 1ms per pane.KiB/MiB/GiB) or 1000-based (KB/MB/GB)?htop/Activity Monitordiffer. Suggest 1024-based to match macOS Memory column convention.skipExpensive=trueafter 5 consecutive idle polls (src/tab.ts:794). RSS query is cheap enough to keep firing even when idle — a pane sitting on 4 GB while idle is exactly when you want to see it. Don't gate this behindskipExpensive.Risks
Minimal. Reuses existing polling infrastructure and syscall pattern. The Option-based return lets a
proc_pidinfofailure degrade gracefully — pane just doesn't show the badge.Out of scope
References
src/pane.ts:728-758(updateFooter)src/tab.ts:768-880(pollPane)src-tauri/src/process_info.rs:29-97proc_pidinfousage:src-tauri/src/process_info.rs:171(get_process_cwd_full)