Agent Tracking with Task Subagent Types in Claude HUD: A Deep Dive into Transcript Parsing

Claude HUD implements agent tracking by parsing JSON-L transcript entries to detect Task tool uses, extracting subagent_type from the input payload, and maintaining a lifecycle-managed AgentEntry map that updates from "running" to "completed" upon receiving the corresponding tool result.

The jarrodwatts/claude-hud repository provides a terminal heads-up display for Claude Code sessions. At its core, the system performs real-time agent tracking with Task subagent types by analyzing the session transcript stream. This mechanism enables the HUD to visualize when Claude spawns specialized sub-agents—such as search, write, or explore tasks—and monitor their execution status until completion.

How Task Tool Detection Works in src/transcript.ts

The transcript parser in src/transcript.ts processes the session log line-by-line. Within the processEntry function, the system identifies when Claude invokes a sub-agent through the Task tool.

Detecting Task Tool Use Blocks

When the parser encounters a block where type === 'tool_use' and name === 'Task', it triggers the agent creation path. This detection occurs at lines 94-108 in src/transcript.ts:

if (block.type === 'tool_use' && block.name === 'Task') {
  const input = block.input as Record<string, unknown>;
  const agentEntry: AgentEntry = {
    id: block.id,
    type: (input?.subagent_type as string) ?? 'unknown',
    model: (input?.model as string) ?? undefined,
    description: (input?.description as string) ?? undefined,
    status: 'running',
    startTime: timestamp,
  };
  agentMap.set(block.id, agentEntry);
}

Extracting Subagent Type from Input Payload

The parser extracts the subagent_type field from the tool's input payload at line 107. This value categorizes the agent's purpose—common values include search, write, explore, or code. If the field is absent, the system defaults to 'unknown'.

The AgentEntry Data Structure

The AgentEntry interface defined in src/types.ts serves as the canonical data structure for tracked sub-agents:

export interface AgentEntry {
  id: string;                // Same as the tool_use.id
  type: string;              // subagent_type from the Task payload
  model?: string;            // optional model name
  description?: string;      // optional textual description
  status: 'running' | 'completed';
  startTime: Date;
  endTime?: Date;
}

This structure enables the HUD to display rich metadata about each active sub-agent, including its specific type and execution duration.

Tracking Agent Lifecycle: From Running to Completed

The system maintains agent state through a complete lifecycle, from initial detection through completion.

Storing Agents in the Map

Upon detecting a Task tool use, the parser creates an AgentEntry and stores it in agentMap (a Map<string, AgentEntry>) using the tool's unique ID as the key. This occurs at lines 112-114 in src/transcript.ts:

agentMap.set(block.id, agentEntry);

This mapping allows the system to correlate subsequent tool results with their originating agent.

Updating Status on Tool Result

When the parser encounters a tool_result block, it checks whether the tool_use_id matches an entry in agentMap. If found, the system updates the agent's status to "completed" and records the endTime. This logic appears at lines 64-68:

if (block.type === 'tool_result' && block.tool_use_id) {
  const agent = agentMap.get(block.tool_use_id);
  if (agent) {
    agent.status = 'completed';
    agent.endTime = timestamp;
  }
}

Trimming to Recent Agents

After processing the entire transcript, the system retains only the most recent 10 agents to prevent memory bloat and maintain HUD clarity. This trimming occurs at line 69:

result.agents = Array.from(agentMap.values()).slice(-10);

Rendering Tracked Agents in the HUD

The renderAgentsLine function in src/render/agents-line.ts (lines 4-34) formats the tracked agents for terminal display. It selects currently running agents plus the two most recent completed agents, then generates a formatted string showing status icons, agent types, and elapsed time:

const runningAgents = agents.filter(a => a.status === 'running');
const recentCompleted = agents.filter(a => a.status === 'completed').slice(-2);
const toShow = [...runningAgents, ...recentCompleted].slice(-3);

return toShow.map(formatAgent).join('\n');

This ensures the HUD always shows relevant active work while maintaining a compact display.

Summary

  • Task Detection: The parser in src/transcript.ts identifies tool_use blocks with name === 'Task' to trigger agent creation.
  • Type Extraction: The subagent_type field from the tool input determines the agent's categorical type (search, write, etc.).
  • Lifecycle Management: Agents are stored in a Map keyed by tool-use ID, updated to "completed" status upon receiving the matching tool_result, and trimmed to the 10 most recent entries.
  • HUD Rendering: The renderAgentsLine function displays running agents plus recent completions with status icons and timing information.

Frequently Asked Questions

What triggers the creation of an AgentEntry in Claude HUD?

An AgentEntry is created when the transcript parser encounters a tool_use block where the name property equals "Task". This indicates Claude has invoked a sub-agent tool, prompting the system to initialize a new agent record with "running" status and capture metadata like subagent_type from the tool's input payload.

How does the system distinguish between different subagent types?

The system extracts the subagent_type field from the Task tool's input object. This string value—such as "search", "write", "explore", or "code"—is stored directly in the AgentEntry.type property. If the field is missing, the system defaults to "unknown" to ensure graceful handling of malformed or legacy tool calls.

What happens when a Task subagent completes its execution?

When the sub-agent finishes, Claude emits a tool_result block containing the original tool_use_id. The parser looks up this ID in the agentMap, and if found, updates the corresponding AgentEntry by setting status to "completed" and recording the endTime timestamp. This change is immediately reflected in the HUD during the next render cycle.

Why does Claude HUD only display the 10 most recent agents?

After processing the entire transcript, the system explicitly trims the agent list to the last 10 entries using Array.from(agentMap.values()).slice(-10). This design prevents memory accumulation during long sessions and keeps the HUD interface uncluttered, ensuring users see only relevant recent activity rather than an overwhelming historical backlog.

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 →