Context
The heartbeat reports container-level memory only (memory_usage() reads the cgroup in agent/hub-agent.py), and the compose file sizes mem_limit/cpus/pids_limit against MAX_SESSIONS. Nothing attributes usage to individual sessions, and disk isn't tracked at all — worktrees under REPOS_ROOT/.agenthub/worktrees and transcripts under ~/.claude/projects both grow unbounded.
Problem
- When a host container approaches its memory limit, there's no way to see which session is responsible — a runaway build or a huge repo checkout looks the same as six healthy sessions. The only remedy today is guessing or restarting the whole container.
- Worktrees (with
node_modules, build artifacts, etc.) can be large; killed sessions keep their branch but freed worktrees, while stopped-but-never-deleted sessions keep worktrees on disk indefinitely. Transcript JSONLs also accumulate forever and are re-parsed by usage_report() — parse cost grows with history.
Proposal
- Per-session CPU/RSS: each session is a tmux session whose pane PID is queryable (
tmux list-panes -t agent-<id> -F '#{pane_pid}'); walk its process subtree via /proc/<pid>/.. (stdlib-only, matching the repo's no-pip constraint) and sum RSS + utime/stime deltas between beats. Report {rssBytes, cpuPct} in _session_payload().
- Disk:
du-equivalent of the worktree (cheap incremental: full scan on the slow USAGE_EVERY cadence, like usage parsing) plus the transcript directory size.
- UI: add the numbers to the session card, and turn the host memory line into used/limit with a top-consumer hint. Sort options by RSS (pairs with the dashboard filtering issue).
- Alert hook: host memory > N% of limit is a natural ntfy alert (edge-triggered like the others in
heartbeatAlerts()), now actionable because the payload says which session to kill.
Touchpoints
agent/hub-agent.py — proc-tree sampling, _session_payload(), slow-cadence disk scan
agent-hub/server.js — optional memory alert
agent-hub/public/index.html — display
Context
The heartbeat reports container-level memory only (
memory_usage()reads the cgroup inagent/hub-agent.py), and the compose file sizesmem_limit/cpus/pids_limitagainstMAX_SESSIONS. Nothing attributes usage to individual sessions, and disk isn't tracked at all — worktrees underREPOS_ROOT/.agenthub/worktreesand transcripts under~/.claude/projectsboth grow unbounded.Problem
node_modules, build artifacts, etc.) can be large; killed sessions keep their branch but freed worktrees, while stopped-but-never-deleted sessions keep worktrees on disk indefinitely. Transcript JSONLs also accumulate forever and are re-parsed byusage_report()— parse cost grows with history.Proposal
tmux list-panes -t agent-<id> -F '#{pane_pid}'); walk its process subtree via/proc/<pid>/..(stdlib-only, matching the repo's no-pip constraint) and sum RSS + utime/stime deltas between beats. Report{rssBytes, cpuPct}in_session_payload().du-equivalent of the worktree (cheap incremental: full scan on the slowUSAGE_EVERYcadence, like usage parsing) plus the transcript directory size.heartbeatAlerts()), now actionable because the payload says which session to kill.Touchpoints
agent/hub-agent.py— proc-tree sampling,_session_payload(), slow-cadence disk scanagent-hub/server.js— optional memory alertagent-hub/public/index.html— display