# How Tool Activity Tracking Works in Claude HUD: Extracting tool_use and tool_result Blocks from Transcript JSONL

> Discover how Claude HUD tracks tool activity by parsing transcript JSONL for tool_use and tool_result blocks. See how it extracts and updates tool completion status.

- Repository: [Jarrod Watts/claude-hud](https://github.com/jarrodwatts/claude-hud)
- Tags: internals
- Published: 2026-03-18

---

**Claude HUD implements tool activity tracking by streaming the session transcript as line-delimited JSON, detecting `tool_use` blocks to create running tool entries, and matching subsequent `tool_result` blocks by ID to update completion status.**

The `jarrodwatts/claude-hud` repository provides a terminal heads-up display for Claude Code sessions. At its core, the tool activity tracking system parses the live transcript file to extract every tool invocation and its outcome. This functionality resides primarily in [`src/transcript.ts`](https://github.com/jarrodwatts/claude-hud/blob/main/src/transcript.ts), which processes the JSONL stream and maintains state maps for active tools.

## Parsing the Transcript JSONL Stream

### Streaming Line-by-Line with parseTranscript

The entry point for tool activity tracking is the `parseTranscript` function in [`src/transcript.ts`](https://github.com/jarrodwatts/claude-hud/blob/main/src/transcript.ts). Rather than loading the entire transcript into memory, it opens the file as a read stream and processes it line-by-line using Node.js `readline`.

This approach is critical for performance, as Claude Code transcripts can grow large during extended sessions. The function iterates through each line, parses valid JSON into a `TranscriptLine` object, and passes it to `processEntry` for content analysis.

### The TranscriptLine Structure

Each line in the transcript represents a message or event in the Claude session. The `TranscriptLine` type contains a `content` array where individual blocks—text, tool uses, and tool results—are stored. The parser examines each block's `type` property to determine how to handle it.

## Detecting and Tracking Tool Invocations

### Identifying tool_use Blocks

Inside `processEntry`, the code walks every block in the `content` array. When it encounters a block where `block.type === 'tool_use'`, it validates that the block contains an `id` and `name` property. These fields are essential for tracking, as the `id` serves as the unique key for matching results later.

### Creating ToolEntry Objects

Upon detecting a valid `tool_use` block, the system creates a `ToolEntry` object with the following properties:

- `id`: The tool invocation ID from the block
- `name`: The tool name (e.g., "Read", "Write", "Task")
- `status`: Set to `'running'` immediately upon creation
- `startTime`: Timestamp from the current transcript line

This object captures the state of the tool at the moment of invocation.

### Storing Active Tools in toolMap

The `ToolEntry` is stored in a `Map<string, ToolEntry>` called `toolMap`, keyed by the tool's `id`. This map maintains the state of all currently running tools, allowing the system to update them when results arrive. The use of a Map ensures O(1) lookups when matching results to invocations.

## Matching Tool Results to Running Tools

### Processing tool_result Blocks

When `processEntry` encounters a block with `type === 'tool_result'`, it extracts the `tool_use_id` property. This ID corresponds to the `id` assigned to the `tool_use` block that initiated the tool call. The system looks up this ID in `toolMap` to find the matching `ToolEntry`.

### Updating Status and Completion Time

If a matching entry exists, the system updates the `ToolEntry` with the result information:

- `status`: Changed to `'completed'` if successful, or `'error'` if the result block has `is_error: true`
- `endTime`: Set to the timestamp of the current transcript line

This update completes the lifecycle of the tool invocation, capturing both the start and end times for duration calculation.

### Handling Agent-Specific Task Tools

The same mechanism applies to agent tracking via `agentMap`. When the `Task` tool (used for sub-agent delegation) is invoked, it creates an `AgentEntry` in `agentMap`. The subsequent `tool_result` for that Task updates the agent's status to `'completed'` using the same ID-matching logic.

## Rendering the Tool Activity Line

After processing the transcript, the `parseTranscript` function converts the `toolMap` and `agentMap` to arrays and truncates them to the most recent entries (last 20 tools, last 10 agents). This data is passed to [`src/render/tools-line.ts`](https://github.com/jarrodwatts/claude-hud/blob/main/src/render/tools-line.ts), which formats the tool activity into a concise status line showing running and recently completed tools.

## Code Examples

### Parsing and Filtering Running Tools

This example demonstrates how to use the `parseTranscript` function to extract currently running tools from a Claude session transcript:

```typescript
import { parseTranscript } from './transcript.js';

async function showRunningTools(path: string) {
  const data = await parseTranscript(path);
  console.log('Running tools:');
  data.tools
    .filter(t => t.status === 'running')
    .forEach(t => {
      console.log(`- ${t.name} (${t.id}) started at ${t.startTime.toISOString()}`);
    });
}

// Example usage (the path is supplied by Claude HUD at runtime)
showRunningTools('/home/user/.claude/transcript.jsonl');

```

### Rendering the Status Line

This simplified example shows how the parsed tool data flows into the renderer:

```typescript
import { renderToolsLine } from './render/tools-line.js';
import { parseTranscript } from './transcript.js';

export async function renderStatus(transcriptPath: string) {
  const transcript = await parseTranscript(transcriptPath);
  const line = renderToolsLine(transcript.tools);
  process.stdout.write(line + '\n');
}

```

## Summary

- **Streaming parser**: `parseTranscript` in [`src/transcript.ts`](https://github.com/jarrodwatts/claude-hud/blob/main/src/transcript.ts) processes the JSONL transcript line-by-line to minimize memory usage.
- **Block detection**: The system identifies `tool_use` blocks to create `ToolEntry` objects with `status: 'running'` and stores them in a `toolMap` keyed by tool ID.
- **Result matching**: Incoming `tool_result` blocks are matched to running tools via `tool_use_id`, updating status to `'completed'` or `'error'` and recording `endTime`.
- **Agent support**: The same pattern tracks sub-agent `Task` tools using `agentMap`.
- **Rendering**: Results are truncated to recent entries and formatted by [`src/render/tools-line.ts`](https://github.com/jarrodwatts/claude-hud/blob/main/src/render/tools-line.ts) for display.

## Frequently Asked Questions

### What file format does Claude HUD use for transcripts?

Claude HUD reads the Claude Code session transcript as a line-delimited JSON (JSONL) file. Each line represents a discrete event or message in the conversation, containing content blocks that may include text, tool invocations, or tool results. The `parseTranscript` function treats this as a read stream to handle large files efficiently.

### How does the tool tracker handle errors in tool execution?

When processing a `tool_result` block, the code checks the `is_error` property. If `is_error` is true, the matching `ToolEntry` in `toolMap` has its `status` set to `'error'` instead of `'completed'`. This allows the renderer to display failed tool invocations distinctly from successful ones, providing immediate visual feedback about execution problems.

### Can I use the parseTranscript function outside of Claude HUD?

Yes, the `parseTranscript` function is designed as a standalone utility that accepts a file path string and returns a `TranscriptData` object containing arrays of tools and agents. You can import it into other TypeScript projects to analyze Claude Code transcripts programmatically, filter for specific tool usage patterns, or build custom analytics dashboards.

### Where does the tool activity information get displayed?

After parsing, the tool activity data flows to [`src/render/tools-line.ts`](https://github.com/jarrodwatts/claude-hud/blob/main/src/render/tools-line.ts), which formats the information into a concise status line. This line displays currently running tools and recently completed ones directly in the terminal HUD, giving users real-time visibility into Claude Code's tool usage without interrupting their workflow.