# What Is the Sensor Component in ADR and How Does It Collect Agent Telemetry?

> Discover the Sensor component in Uber's ADR. Learn how it collects AI agent telemetry by gathering and normalizing raw interaction logs for analysis.

- Repository: [Uber Open Source/ADR](https://github.com/uber/ADR)
- Tags: deep-dive
- Published: 2026-08-06

---

**The Sensor is the telemetry-ingestion layer of Uber's ADR (Automated Detection and Response) repository that gathers raw interaction logs from AI coding assistants and normalizes them into a unified, analyzable format.**

The Sensor bridges the gap between heterogeneous, platform-specific telemetry produced by AI agents like Claude, Cursor, Cline, Warp, Codex, and Claude Desktop and the downstream security analysis pipelines of ADR. This article breaks down exactly how the Sensor component works under the hood, with reference to the actual source implementation in `uber/ADR`.

## Core Architecture: The AgentObserver Class

At the heart of the Sensor lies the **`AgentObserver`** class, defined in [`Sensor/adr_sensor/observer.py`](https://github.com/uber/ADR/blob/main/Sensor/adr_sensor/observer.py). This class orchestrates the entire telemetry collection pipeline through a four-stage process.

### Stage 1: Parser Discovery and Initialization

When instantiated, `AgentObserver` creates a set of parser objects. Each parser knows how to locate and decode log files for a specific agent:

- `ClaudeParser` → `~/.cache/adr_sensor/claude/*.json`
- `CursorParser` → Cursor-specific log paths
- `ClineParser`, `WarpParser`, `CodexParser`, `ClaudeDesktopParser` → respective default directories

Parsers can use their default directories or accept a user-supplied path override.

### Stage 2: Log Parsing and Normalization

Each discovered log file is parsed into an **`AgentEvent`** data class, defined in [`Sensor/adr_sensor/schemas/agent_event_schema.py`](https://github.com/uber/ADR/blob/main/Sensor/adr_sensor/schemas/agent_event_schema.py). This schema normalizes disparate fields across all supported agents into a single consistent structure:

| Normalized Field | Description |
|------------------|-------------|
| UUID | Unique event identifier |
| Timestamp | Standardized temporal reference |
| Session ID | Correlated conversation grouping |
| Chat turns | Message sequence within a session |
| Tool usage | Which tools the agent invoked |
| Host metadata | System configuration context |
| Content hash | Integrity verification |

### Stage 3: Noise Filtering

The `AgentEvent.has_meaningful_content()` method filters out low-value telemetry:

- Empty conversations
- Single-message error states
- Known boilerplate strings

This ensures downstream analysis focuses on actionable security-relevant activity.

### Stage 4: Aggregation and Output

Cleaned events are aggregated with optional system-configuration records, then output in multiple formats: tabular summaries to stdout, consolidated JSON/JSON-L files, or individual session files for incremental processing.

## Code Implementation: Using AgentObserver

The following code demonstrates the exact implementation found in [`Sensor/adr_sensor/observer.py`](https://github.com/uber/ADR/blob/main/Sensor/adr_sensor/observer.py):

```python
from adr_sensor.observer import AgentObserver

# 1️⃣ Create the observer (default output dir = ./output)

observer = AgentObserver()

# 2️⃣ Ingest logs from every supported agent

events, configs = observer.ingest_all()      # source_filter defaults to "all"

# 3️⃣ Show a quick human-readable summary

observer.display_summary(events, configs)

# 4️⃣ Persist the unified telemetry for later analysis

observer.save_to_file(events, configs, output_format="json")

```

### CLI Entry Point

The Sensor exposes a minimal CLI in [`Sensor/adr_sensor/cli.py`](https://github.com/uber/ADR/blob/main/Sensor/adr_sensor/cli.py) that wraps the same pipeline:

```python

# Run from command line

# $ python -m adr_sensor.cli

# This executes:

# - observer.ingest_all()

# - observer.display_summary()

# - observer.save_to_file()

```

## Advanced Sensor Usage Patterns

### Saving Individual Session Files

For incremental downstream processing, save each session as a separate file:

```python
from pathlib import Path

output_dir = Path("/tmp/adr_sessions")
saved_paths = observer.save_sessions_to_individual_files(events, output_dir)
print(f"Saved {len(saved_paths)} session files to {output_dir}")

```

### Filtering Already-Processed Sessions

Avoid reprocessing duplicate telemetry when running collection repeatedly:

```python
new_events = observer.filter_entries_by_existing_files(events, output_dir)
print(f"{len(new_events)} new/updated sessions to process")

```

## Key Source Files in the Sensor Component

| File Path | Purpose |
|-----------|---------|
| [`Sensor/adr_sensor/observer.py`](https://github.com/uber/ADR/blob/main/Sensor/adr_sensor/observer.py) | Core `AgentObserver` orchestrator—creates parsers, aggregates events, displays summaries, writes output |
| [`Sensor/adr_sensor/schemas/agent_event_schema.py`](https://github.com/uber/ADR/blob/main/Sensor/adr_sensor/schemas/agent_event_schema.py) | `AgentEvent` data class with UUID generation, content hashing, and `has_meaningful_content()` helper |
| [`Sensor/adr_sensor/cli.py`](https://github.com/uber/ADR/blob/main/Sensor/adr_sensor/cli.py) | Command-line entry point for local or CI pipeline execution |
| `Sensor/adr_sensor/parsers/` | Modular parsers: [`claude_parser.py`](https://github.com/uber/ADR/blob/main/claude_parser.py), [`cursor_parser.py`](https://github.com/uber/ADR/blob/main/cursor_parser.py), [`cline_parser.py`](https://github.com/uber/ADR/blob/main/cline_parser.py), [`warp_parser.py`](https://github.com/uber/ADR/blob/main/warp_parser.py), [`codex_parser.py`](https://github.com/uber/ADR/blob/main/codex_parser.py), [`claude_desktop_parser.py`](https://github.com/uber/ADR/blob/main/claude_desktop_parser.py) |
| [`Sensor/README.md`](https://github.com/uber/ADR/blob/main/Sensor/README.md) | Package overview, installation, and usage documentation |

## Extending the Sensor for New AI Agents

The Sensor's parser-based architecture enables straightforward extension. To add support for a new AI agent:

1. Create a new parser module in `Sensor/adr_sensor/parsers/`
2. Implement log location and decoding logic
3. Return `AgentEvent` instances with normalized fields
4. Register the parser in `AgentObserver`'s initialization

This design ensures ADR maintains a consistent view of agent activity regardless of how the underlying AI assistant ecosystem evolves.

## Summary

- **The Sensor** is ADR's telemetry-ingestion layer, implemented primarily through the `AgentObserver` class in [`Sensor/adr_sensor/observer.py`](https://github.com/uber/ADR/blob/main/Sensor/adr_sensor/observer.py).
- **Agent telemetry collection** works via pluggable parsers that discover, parse, and normalize logs from Claude, Cursor, Cline, Warp, Codex, and Claude Desktop into unified `AgentEvent` objects.
- **Noise reduction** happens through `AgentEvent.has_meaningful_content()`, filtering empty or boilerplate interactions before downstream analysis.
- **Flexible output options** include CLI summaries, consolidated JSON files, or individual session files for incremental processing.
- **Extensible architecture** allows new AI agents to be supported by adding parser modules without modifying core collection logic.

## Frequently Asked Questions

### What AI agents does the ADR Sensor currently support?

The Sensor supports Claude, Cursor, Cline, Warp, Codex, and Claude Desktop as of the latest implementation in `uber/ADR`. Each agent has a dedicated parser module in `Sensor/adr_sensor/parsers/` that handles its specific log format and default storage location.

### How does the Sensor handle different log formats from various AI agents?

The `AgentObserver` delegates format-specific parsing to specialized parser classes. Each parser knows how to locate its agent's logs and extract relevant fields. The parsers then instantiate `AgentEvent` objects from [`Sensor/adr_sensor/schemas/agent_event_schema.py`](https://github.com/uber/ADR/blob/main/Sensor/adr_sensor/schemas/agent_event_schema.py), which normalizes heterogeneous data into a consistent schema regardless of source agent.

### Can the Sensor run in automated pipelines or only interactively?

Both. The [`Sensor/adr_sensor/cli.py`](https://github.com/uber/ADR/blob/main/Sensor/adr_sensor/cli.py) module provides a command-line interface suitable for CI/CD pipelines, cron jobs, or local development. The CLI calls `AgentObserver.ingest_all()`, `display_summary()`, and `save_to_file()` in sequence, making unattended operation straightforward with appropriate output directory configuration.

### Where does the Sensor store collected telemetry?

By default, `AgentObserver` uses `./output` as its working directory. You can override this via the `output_dir` parameter. The component supports multiple persistence modes: consolidated JSON/JSON-L files via `save_to_file()`, or individual session files via `save_sessions_to_individual_files()` for incremental processing workflows.