How the oh-my-claudecode HUD Statusline Renders Real-Time Orchestration Metrics

The oh-my-claudecode HUD renders real-time orchestration metrics by polling three independent JSON data sources—Claude Code transcripts, OMC runtime state files, and external APIs—then aggregating them into a declarative HudRenderContext that pure renderer functions convert into a concise, color-coded terminal statusline.

The HUD (Heads-Up Display) in oh-my-claudecode is a lightweight terminal statusline that provides continuous visibility into multi-agent orchestration states. Unlike static logging, it maintains a live view of active agents, loop iterations, rate limits, and background tasks by re-rendering the entire pipeline on a configurable interval. Understanding how this real-time rendering pipeline works requires examining the three distinct data flows that feed the display.

The Three Data Sources Driving the HUD

The HUD operates as a pure-function view over immutable JSON snapshots. It combines three independent data streams to build a complete picture of the orchestration state.

Claude Code Transcript Stream

The primary data source is the live JSON stream from Claude Code (or a cached copy when stdin is a TTY). In src/hud/stdin.ts, the readStdinCache() function retrieves the latest transcript, while src/hud/transcript.ts parses this into structured metrics:

  • Active agents and their statuses
  • Pending todos and thinking states
  • Tool-call, agent-call, and skill-call counters
  • Pending permissions and session health tokens

OMC Runtime State Files

Persistent state files written by various "modes" (Ralph, Ultrawork, Autopilot, PRD, and background tasks) provide loop-level orchestration data. The src/hud/omc-state.ts module exports read helpers that fetch JSON blobs from ~/.omc/state/, while src/team/team-status.ts aggregates worker heartbeats. These files contain:

  • Loop counters and iteration limits
  • PRD story IDs and autopilot modes
  • Background task progress and session start times

External Rate-Limit APIs

When elements.rateLimits is enabled, the HUD fetches Anthropic or z.ai usage statistics via src/hud/usage-api.ts. Optional custom provider commands defined in src/hud/custom-rate-provider.ts allow integration with proprietary rate-limit buckets, returning 5-hour and weekly usage percentages.

Entry Point and Watch Loop

The CLI command omc hud executes src/hud/index.ts. For continuous updates, the --watch flag invokes src/cli/hud-watch.ts, which implements runHudWatchLoop():

// src/cli/hud-watch.ts (excerpt)
while (!shouldStop) {
  await options.hudMain(true, skipInit);
  skipInit = true;
  await new Promise(r => setTimeout(r, options.intervalMs));
}

This loop executes every intervalMs (default 1000ms), calling the main HUD function with readStdinCache() enabled. This architecture ensures the statusline updates even when the parent process’s stdin is a TTY, decoupling the display from the actual Claude Code process.

Building the Render Context

The main() function in src/hud/index.ts acts as the aggregation layer. It constructs a HudRenderContext object by querying all three data sources:

const context: HudRenderContext = {
  // Transcript data
  activeAgents: transcriptData.agents.filter(a => a.status === "running"),
  todos: transcriptData.todos,
  toolCallCount: transcriptData.toolCallCount,
  agentCallCount: transcriptData.agentCallCount,
  skillCallCount: transcriptData.skillCallCount,
  thinkingState: transcriptData.thinkingState,
  pendingPermission: transcriptData.pendingPermission,
  
  // OMC state files
  ralph,
  ultrawork,
  prd,
  autopilot,
  
  // External metrics
  rateLimitsResult,
  customBuckets,
  
  // UI metadata
  cwd,
  modelName: getModelName(stdin),
  omcVersion,
  updateAvailable,
};

Rate-limit data is fetched only when enabled, and session summaries refresh via a fire-and-forget child process (spawnSessionSummaryScript) to avoid blocking the render loop.

Rendering the Statusline Elements

All rendering logic resides in src/hud/render.ts. The function iterates over HudConfig.elements (populated from ~/.omc/config.json or defaults) and dispatches to specialized renderers in src/hud/elements/* based on which metrics are enabled.

Orchestration-Specific Renderers

The following element renderers display live orchestration metrics:

The renderer respects HudConfig.maxWidth and wrapMode settings, joining header elements with | separators and truncating or wrapping based on terminal constraints.

Achieving Real-Time Visibility

Because the watch loop re-executes the entire pipeline each tick, the HUD achieves real-time synchronization through file-system polling and API caching:

  1. Agent state changes appear immediately when transcript.jsonl gains a new "running" entry.
  2. Ralph/Autopilot iterations update as ~/.omc/state/*/ralph.json or autopilot.json files are rewritten by the respective modes.
  3. Rate-limit bars refresh every usageApiPollIntervalMs (default 90 seconds) via getUsage().
  4. Background task completion removes entries from readHudState() results instantly.

This pull-based architecture means the HUD never holds persistent state; each render cycle is idempotent, reading the latest JSON snapshots and producing a fresh statusline.

Usage Examples


# One-off render (used by shell prompts)

omc hud

# Continuous live view with 0.5s refresh

omc hud --watch --interval 500

# Minimal preset for narrow terminals

omc hud --preset minimal

# Force custom width and wrapping

omc hud --max-width 80 --wrap-mode wrap

Summary

  • The HUD aggregates three data flows: Claude Code transcripts (src/hud/transcript.ts), OMC runtime state files (src/hud/omc-state.ts), and external rate-limit APIs (src/hud/usage-api.ts).
  • src/cli/hud-watch.ts implements runHudWatchLoop() to re-render every 1000ms by default.
  • src/hud/index.ts builds a HudRenderContext containing active agents, loop states, and usage metrics.
  • src/hud/render.ts dispatches to element-specific renderers in src/hud/elements/ to generate the final statusline.
  • The system uses a stateless, pull-based architecture where each tick reads fresh JSON snapshots to ensure real-time accuracy.

Frequently Asked Questions

How does the HUD handle stdin when running in watch mode?

When invoked with --watch, the HUD reads from readStdinCache() in src/hud/stdin.ts rather than blocking on stdin. This allows the statusline to update continuously even when the parent process is a TTY, as the watch loop accesses cached transcript data written by the main Claude Code process.

Where are the Ralph and Autopilot loop counters stored?

Loop iteration data is persisted in JSON files under ~/.omc/state/ (specifically ralph.json and autopilot.json). The src/hud/omc-state.ts module provides type-safe read helpers, while src/hud/elements/ralph.ts and src/hud/elements/autopilot.ts parse these files to render counters like Rα1/7 and apply threshold-based color coding.

Can I customize which metrics appear in the statusline?

Yes. The HUD respects the elements configuration object in ~/.omc/config.json. Each boolean flag (e.g., agents, rateLimits, background) controls whether src/hud/render.ts invokes the corresponding renderer in src/hud/elements/. You can also apply presets using omc hud --preset minimal to quickly toggle common metric combinations.

How often does the HUD fetch external rate-limit data?

By default, the Anthropic/z.ai usage API is polled every 90 seconds (usageApiPollIntervalMs). This cached value is then read from rateLimitsResult in the render context on every tick, ensuring the statusline remains responsive while respecting API rate limits.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →