dynaum/agdog

Agent-aware terminal resource monitor: htop and nvitop fused, grouped by the agent that owns each process.

Rust

2

45 commits

updated Sep 28, 2026

See the code

See what people are saying

SourceMessageScoreDate

Agdog – htop and nvitop, fused and agent-aware

1

Sep 28, 2026

README

🐕 agdog

htop and nvitop, fused and agent-aware.

One terminal pane that groups CPU, RAM, GPU, and VRAM by the agent that owns each process, then tells you which one is stuck, runaway, or eating your memory.

CI License: MIT Rust Platform

agdog demo


The problem

You run local AI work: a ComfyUI render, a kohya_ss LoRA training run, two Ollama models, a couple of coding agents. Every monitor on your machine shows you PIDs, CPU%, and a wall of VRAM numbers. None of them tells you which agent owns that load, whether a job wedged, or what it cost.

Memory is exclusive. One runaway render starves everything else, and you find out only when something crashes at 2am. htop shows a process. nvitop shows a device. Neither shows you the agent.

agdog answers the question you actually have:

Which agent is eating my VRAM right now, and is it stuck?

What you see

agdog reads your real processes, groups them by the agent that spawned them, and paints one live pane:

  • Aggregate strip — working / idle / stuck / runaway counts, total GPU / VRAM / CPU / RAM, and cost per hour.
  • Per-GPU panels — nvitop-style UTL and MEM bars with temperature and power.
  • Agents table — one row per agent, grouped from its processes: kind (render / train / infer / coding), GPU%, VRAM, CPU%, memory, cost, uptime, and a color-coded state.
  • Detail pane — a 60-second GPU sparkline plus stats for the selected agent.
  • Alerts — every runaway, crashed, or stuck agent with a one-key action.

State colors tell the story at a glance: 🟢 working · ⚪ idle · 🟡 stuck · 🔴 runaway · 🟣 crashed.

Install

Homebrew (macOS arm64/x86_64, Linux x86_64):

brew install dynaum/tap/agdog

Windows (one-liner, no prerequisites):

irm https://raw.githubusercontent.com/dynaum/agdog/master/install.ps1 | iex

Downloads the latest release, installs agdog.exe to %LOCALAPPDATA%\agdog, and adds it to your PATH.

From source (requires Rust 1.85+ for edition 2024):

cargo install --git https://github.com/dynaum/agdog

Prebuilt binaries are attached to every release:

PlatformTargets
macOSaarch64-apple-darwin, x86_64-apple-darwin
Linuxx86_64-unknown-linux-gnu, aarch64-unknown-linux-gnu (glibc 2.34+, so Debian 12, Ubuntu 22.04, RHEL/Rocky 9 and Amazon Linux 2023 all work), x86_64-unknown-linux-musl (fully static, Alpine)
Windowsx86_64-pc-windows-msvc

Every archive is listed in the SHA256SUMS file published with the release.

Quick start

agdog

That's it. agdog detects your machine and shows real numbers automatically, no flags, no sudo:

  • Mac — live GPU utilization and unified memory via IOKit.
  • Linux / Windows with an NVIDIA GPU — per-process VRAM and utilization via NVML.
  • Windows (any GPU) — VRAM via DXGI and utilization via PDH counters.
  • Anywhere else — a mock GPU keeps the view alive so the tool still runs.

Usage

agdog                      # live monitor
agdog --interval 2         # refresh every 2 seconds
agdog --gpu-hourly 2.50    # derive per-agent cost at $2.50 / GPU-hour
agdog watch                # subscribe to the event socket, print JSON events
agdog agents               # print the detected agents once and exit

agdog identifies agents by their program name, not path substrings, so it separates real CLIs (each claude session, ollama, aider, ...) from GUI apps and system services. Parallel sessions are named by their project directory (claude:myproject); child processes (node, MCP servers) roll into their session; everything else lands in one unassigned row.

Keys inside the TUI:

KeyAction
qquit
j / kselect an agent (also ↑ / ↓)
scycle sort column (gpu/cpu/mem/cost/name)
ashow/hide other processes (the unassigned row)
/filter by agent name

By default the table shows only your agents; press a to also show the unassigned row (everything that isn't an agent: the OS, GUI apps, background daemons).

How it works

Attribution is the core idea. agdog maps each process to an agent with layered heuristics, highest confidence first:

  1. An explicit AGENT_ID environment tag. Export it and the process is grouped under that name whatever the binary is called: AGENT_ID=render-batch ./my-worker. Linux only. macOS refuses to expose another process's environment, even a child of the reading process, so the tag is invisible there and attribution falls through to the signature below.
  2. Command-line signatures (comfyui, kohya, ollama, vllm, laya, claude, ...).
  3. Process-tree ancestry, so child workers inherit their parent's agent.

Classification watches utilization and hold-time to label each agent working, idle, stuck (memory held with no activity), runaway (pegged and sustained), or crashed.

Subagents nest under their parent agent (a SUB count on the parent, indented ↳ rows). agdog finds them three ways: child agent processes via the tree, Claude Code Task sidechains read from the session transcript (isSidechain), and agents that report their subagents over the socket.

The socket API is what makes agdog agent-native rather than a dashboard. agdog streams state-change events as JSON lines over the platform's local IPC primitive: a Unix socket at $XDG_RUNTIME_DIR/agdog.sock, or a named pipe at \\.\pipe\agdog on Windows. Both are access-controlled by the OS and neither opens a network port. The protocol is identical, so a client only needs the right name. An orchestrator, or the agents themselves, subscribe and react to a stuck or runaway job instead of scraping the screen:

$ agdog watch
{"kind":"state_changed","agent_id":"kohya-lora","from":"working","to":"stuck","ts_secs":842}
{"kind":"state_changed","agent_id":"vllm-serve","from":"working","to":"runaway","ts_secs":905}

Backends

BackendSelected onWhat you get
Apple SiliconmacOS (auto)GPU utilization via IOKit ioreg + unified memory via sysinfo. No sudo.
NVIDIALinux / Windows (auto)Per-process VRAM and utilization via NVML (runtime driver load).
DXGI + PDHWindows (auto)Per-adapter VRAM via DXGI and utilization via PDH counters (any GPU).
NonefallbackNo GPU panel. Shown when no real backend initializes.
MockAGDOG_DEMO=1 onlyDeterministic fake GPUs, for screenshots and the demo GIF.

The backend is chosen by your OS at build time. When no real backend initializes (no discrete GPU, or a driver that failed to load) agdog reports no readable GPU rather than inventing devices. Fabricated GPU numbers appear only under AGDOG_DEMO=1, and the footer labels them mock (simulated). The live backend name is always shown in the footer.

Status

Early but complete and runnable. Real process metrics work today on all three platforms.

Verified per platform:

  • macOS — fully exercised. Attribution, per-core CPU, and GPU utilization via ioreg all read real data. Covered by CI. AGENT_ID tagging cannot work here (see above).
  • Linux — process, CPU, memory, and AGENT_ID attribution verified on real hosts. The NVML GPU path has no hardware coverage yet, so it is untested against a real card.
  • Windows — attribution, the cwd slug, the named-pipe socket, and DXGI adapter enumeration each run as tests on a real Windows host in CI. The remaining gap is GPU hardware: the runner has a virtual adapter, so VRAM and utilization numbers are unverified under real load, and per-process VRAM is not implemented.

Contributions and hardware reports welcome, particularly from NVIDIA Linux hosts and Windows machines with a real GPU.

Stack

Rust · ratatui · sysinfo · nvml-wrapper. A single binary with no install-time dependencies. The musl build is fully static. The glibc and macOS builds link the system libc, the NVIDIA backend loads the driver library at runtime, and the macOS backend shells out to ioreg.

Changelog

See CHANGELOG.md.

License

MIT © Elber Ribeiro

dynaum/agdog

Agent-aware terminal resource monitor: htop and nvitop fused, grouped by the agent that owns each process.

Rust

2

45 commits

updated Sep 28, 2026

See the code

See what people are saying

SourceMessageScoreDate

Agdog – htop and nvitop, fused and agent-aware

1

Sep 28, 2026

README

🐕 agdog

htop and nvitop, fused and agent-aware.

One terminal pane that groups CPU, RAM, GPU, and VRAM by the agent that owns each process, then tells you which one is stuck, runaway, or eating your memory.

CI License: MIT Rust Platform

agdog demo


The problem

You run local AI work: a ComfyUI render, a kohya_ss LoRA training run, two Ollama models, a couple of coding agents. Every monitor on your machine shows you PIDs, CPU%, and a wall of VRAM numbers. None of them tells you which agent owns that load, whether a job wedged, or what it cost.

Memory is exclusive. One runaway render starves everything else, and you find out only when something crashes at 2am. htop shows a process. nvitop shows a device. Neither shows you the agent.

agdog answers the question you actually have:

Which agent is eating my VRAM right now, and is it stuck?

What you see

agdog reads your real processes, groups them by the agent that spawned them, and paints one live pane:

  • Aggregate strip — working / idle / stuck / runaway counts, total GPU / VRAM / CPU / RAM, and cost per hour.
  • Per-GPU panels — nvitop-style UTL and MEM bars with temperature and power.
  • Agents table — one row per agent, grouped from its processes: kind (render / train / infer / coding), GPU%, VRAM, CPU%, memory, cost, uptime, and a color-coded state.
  • Detail pane — a 60-second GPU sparkline plus stats for the selected agent.
  • Alerts — every runaway, crashed, or stuck agent with a one-key action.

State colors tell the story at a glance: 🟢 working · ⚪ idle · 🟡 stuck · 🔴 runaway · 🟣 crashed.

Install

Homebrew (macOS arm64/x86_64, Linux x86_64):

brew install dynaum/tap/agdog

Windows (one-liner, no prerequisites):

irm https://raw.githubusercontent.com/dynaum/agdog/master/install.ps1 | iex

Downloads the latest release, installs agdog.exe to %LOCALAPPDATA%\agdog, and adds it to your PATH.

From source (requires Rust 1.85+ for edition 2024):

cargo install --git https://github.com/dynaum/agdog

Prebuilt binaries are attached to every release:

PlatformTargets
macOSaarch64-apple-darwin, x86_64-apple-darwin
Linuxx86_64-unknown-linux-gnu, aarch64-unknown-linux-gnu (glibc 2.34+, so Debian 12, Ubuntu 22.04, RHEL/Rocky 9 and Amazon Linux 2023 all work), x86_64-unknown-linux-musl (fully static, Alpine)
Windowsx86_64-pc-windows-msvc

Every archive is listed in the SHA256SUMS file published with the release.

Quick start

agdog

That's it. agdog detects your machine and shows real numbers automatically, no flags, no sudo:

  • Mac — live GPU utilization and unified memory via IOKit.
  • Linux / Windows with an NVIDIA GPU — per-process VRAM and utilization via NVML.
  • Windows (any GPU) — VRAM via DXGI and utilization via PDH counters.
  • Anywhere else — a mock GPU keeps the view alive so the tool still runs.

Usage

agdog                      # live monitor
agdog --interval 2         # refresh every 2 seconds
agdog --gpu-hourly 2.50    # derive per-agent cost at $2.50 / GPU-hour
agdog watch                # subscribe to the event socket, print JSON events
agdog agents               # print the detected agents once and exit

agdog identifies agents by their program name, not path substrings, so it separates real CLIs (each claude session, ollama, aider, ...) from GUI apps and system services. Parallel sessions are named by their project directory (claude:myproject); child processes (node, MCP servers) roll into their session; everything else lands in one unassigned row.

Keys inside the TUI:

KeyAction
qquit
j / kselect an agent (also ↑ / ↓)
scycle sort column (gpu/cpu/mem/cost/name)
ashow/hide other processes (the unassigned row)
/filter by agent name

By default the table shows only your agents; press a to also show the unassigned row (everything that isn't an agent: the OS, GUI apps, background daemons).

How it works

Attribution is the core idea. agdog maps each process to an agent with layered heuristics, highest confidence first:

  1. An explicit AGENT_ID environment tag. Export it and the process is grouped under that name whatever the binary is called: AGENT_ID=render-batch ./my-worker. Linux only. macOS refuses to expose another process's environment, even a child of the reading process, so the tag is invisible there and attribution falls through to the signature below.
  2. Command-line signatures (comfyui, kohya, ollama, vllm, laya, claude, ...).
  3. Process-tree ancestry, so child workers inherit their parent's agent.

Classification watches utilization and hold-time to label each agent working, idle, stuck (memory held with no activity), runaway (pegged and sustained), or crashed.

Subagents nest under their parent agent (a SUB count on the parent, indented ↳ rows). agdog finds them three ways: child agent processes via the tree, Claude Code Task sidechains read from the session transcript (isSidechain), and agents that report their subagents over the socket.

The socket API is what makes agdog agent-native rather than a dashboard. agdog streams state-change events as JSON lines over the platform's local IPC primitive: a Unix socket at $XDG_RUNTIME_DIR/agdog.sock, or a named pipe at \\.\pipe\agdog on Windows. Both are access-controlled by the OS and neither opens a network port. The protocol is identical, so a client only needs the right name. An orchestrator, or the agents themselves, subscribe and react to a stuck or runaway job instead of scraping the screen:

$ agdog watch
{"kind":"state_changed","agent_id":"kohya-lora","from":"working","to":"stuck","ts_secs":842}
{"kind":"state_changed","agent_id":"vllm-serve","from":"working","to":"runaway","ts_secs":905}

Backends

BackendSelected onWhat you get
Apple SiliconmacOS (auto)GPU utilization via IOKit ioreg + unified memory via sysinfo. No sudo.
NVIDIALinux / Windows (auto)Per-process VRAM and utilization via NVML (runtime driver load).
DXGI + PDHWindows (auto)Per-adapter VRAM via DXGI and utilization via PDH counters (any GPU).
NonefallbackNo GPU panel. Shown when no real backend initializes.
MockAGDOG_DEMO=1 onlyDeterministic fake GPUs, for screenshots and the demo GIF.

The backend is chosen by your OS at build time. When no real backend initializes (no discrete GPU, or a driver that failed to load) agdog reports no readable GPU rather than inventing devices. Fabricated GPU numbers appear only under AGDOG_DEMO=1, and the footer labels them mock (simulated). The live backend name is always shown in the footer.

Status

Early but complete and runnable. Real process metrics work today on all three platforms.

Verified per platform:

  • macOS — fully exercised. Attribution, per-core CPU, and GPU utilization via ioreg all read real data. Covered by CI. AGENT_ID tagging cannot work here (see above).
  • Linux — process, CPU, memory, and AGENT_ID attribution verified on real hosts. The NVML GPU path has no hardware coverage yet, so it is untested against a real card.
  • Windows — attribution, the cwd slug, the named-pipe socket, and DXGI adapter enumeration each run as tests on a real Windows host in CI. The remaining gap is GPU hardware: the runner has a virtual adapter, so VRAM and utilization numbers are unverified under real load, and per-process VRAM is not implemented.

Contributions and hardware reports welcome, particularly from NVIDIA Linux hosts and Windows machines with a real GPU.

Stack

Rust · ratatui · sysinfo · nvml-wrapper. A single binary with no install-time dependencies. The musl build is fully static. The glibc and macOS builds link the system libc, the NVIDIA backend loads the driver library at runtime, and the macOS backend shells out to ioreg.

Changelog

See CHANGELOG.md.

License

MIT © Elber Ribeiro

Languages

Rust

94.9%

Shell

3.3%

PowerShell

1.8%