# Real CPU % in the Claude Code status line (macOS)

> Source: <https://gist.github.com/dschinkel/c8b22c226c62da9b8aa33f5bf97d2e9e>
> Published: 2026-10-17 03:21:51+00:00

### Just ask Claude to add this to your statusline, give claude [https://gist.github.com/dschinkel/c8b22c226c62da9b8aa33f5bf97d2e9e](https://gist.github.com/dschinkel/c8b22c226c62da9b8aa33f5bf97d2e9e)

Shows your Mac's real CPU utilization in the Claude Code status line, e.g. `CPU 88% · load: 27.9 tasks | processes: 420 (CLI: 42 · other: 378) | Claude: 3 sessions + 2 subagents | Codex: 1 session | AGY: 1 session`, refreshed every 2 seconds.

- `cpu-util.py` reads the CPU tick counters (`host_statistics` ) and compares them with the previous sample saved in`~/.claude/.cpu-ticks` , so the number is the busy share of the last few seconds — not the load average. First run (or a stale sample) takes a quick 200 ms two-sample read. Any error prints nothing.
- `statusline-cpu-segment.sh` is the snippet to paste into your status-line script. Green under 60%, yellow 60–85%, red over 85%, with the 1-minute load average dimmed beside it and labeled`tasks` . This is an average of tasks running or waiting for CPU/system resources, not an instantaneous task count or percentage.

1. Save `cpu-util.py` as`~/.claude/cpu-util.py` .
2. Save `agent-counts.py` as`~/.claude/agent-counts.py` , then paste`statusline-cpu-segment.sh` into your status-line script where you want the segment.
3. In `~/.claude/settings.json` , add`refreshInterval` to your`statusLine` so the line redraws on its own:

```
"statusLine": {
  "type": "command",
  "command": "bash ~/.claude/statusline-command.sh",
  "refreshInterval": 2
}
```

`refreshInterval` is documented at [https://code.claude.com/docs/en/statusline](https://code.claude.com/docs/en/statusline).

`agent-counts.py` uses macOS `ps` to count running top-level Claude Code, Codex CLI, and Antigravity CLI (`agy`) processes for the current user, including idle sessions. Nested CLI processes of the same host are not additional primary sessions. Codex app-server/MCP/sandbox utility processes are excluded. GUI app conversations, remote sessions, renamed executables, wrappers that hide the CLI, and other users' sessions are outside this count. This is process-based session detection, not a count of CPU tasks; an idle session need not contribute CPU load.

Claude subagents are tracked by their `SubagentStart` and `SubagentStop` lifecycle events, including background agents. Counts are combined across live Claude CLI sessions. Dead sessions and reused process IDs are ignored. This does not use the historical “agents that ran last turn” list. It requires Python 3 and no extra Python packages. Files stay local under `~/.claude/statusline-agents/`; no session data is sent anywhere.

- Unknown subagent counts are hidden; a session count alone does not mean there are zero subagents.
- `2+ subagents` : at least two observed active agents, with incomplete coverage.
- Codex and Antigravity subagent counts are omitted: their lifecycle tracking is not implemented. They may run inside one process and cannot be reliably counted from `ps` .
- With no running primary sessions for a host, its subagent suffix is omitted.

Merge these hook entries into `~/.claude/settings.json`, **preserving all existing hooks**, then restart existing Claude CLI sessions so tracking has a known start. Sessions already running before installation omit unknown subagent counts or show observed lower bounds until restarted. If a lifecycle hook fails or is removed, tracking can become stale until session restart. This is a status indicator, not a billing measurement.

```
{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "python3 -I \"${CLAUDE_CONFIG_DIR:-$HOME/.claude}/agent-counts.py\" --hook",
            "timeout": 5
          }
        ]
      }
    ],
    "SessionEnd": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "python3 -I \"${CLAUDE_CONFIG_DIR:-$HOME/.claude}/agent-counts.py\" --hook",
            "timeout": 5
          }
        ]
      }
    ],
    "SubagentStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "python3 -I \"${CLAUDE_CONFIG_DIR:-$HOME/.claude}/agent-counts.py\" --hook",
            "timeout": 5
          }
        ]
      }
    ],
    "SubagentStop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "python3 -I \"${CLAUDE_CONFIG_DIR:-$HOME/.claude}/agent-counts.py\" --hook",
            "timeout": 5
          }
        ]
      }
    ]
  }
}
```

If `CLAUDE_CONFIG_DIR` is set, install the helper and merge the hooks in that configuration directory instead. The helper and hook command respect it. The original CPU setup still uses `~/.claude/cpu-util.py`.

`processes: N (CLI: A · other: B)` partitions one process snapshot for the current user: `CLI` includes detected CLI root processes and all their descendant processes; `other` includes the remaining processes. `A + B = N`. This counts processes, not OS threads, logical agents, or busy work; idle processes are included. It is separate from the one-minute load average, and is not a breakdown of that average. Subagents running inside a CLI process do not add OS processes. Codex desktop/server processes excluded from CLI session detection fall under `other` unless descended from a counted CLI root.

The snippet starts CPU/load on a new row. Process totals and CLI session counts each get their own row, below your existing model/project row. Claude Code status-line commands support newline-separated output. For example:

```
Claude | ~/my-project | main
CPU 88% · load: 27.9 tasks
processes: 420 (CLI: 42 · other: 378)
Claude: 3 sessions + 2 subagents | Codex: 1 session | AGY: 1 session
```

This keeps the metrics separate from long project or feature names. Very narrow terminals may still wrap or truncate an individual row.
