# How Timestamps Are Parsed in `--timestamps` Mode and Prioritized in claude-video

> Learn how the --timestamps flag parses and prioritizes cue frames in claude-video. Discover how time strings are converted to unique seconds for precise frame extraction.

- Repository: [bradautomates/claude-video](https://github.com/bradautomates/claude-video)
- Tags: internals
- Published: 2026-08-08

---

**The `--timestamps` flag parses comma-separated time strings into sorted, unique seconds, extracts one frame per timestamp, and prioritizes these cue frames above all other automatically selected frames.**

The `bradautomates/claude-video` repository provides a powerful video analysis interface where users can extract specific frames at exact moments using the `--timestamps` flag. Understanding how timestamps are parsed in `--timestamps` mode and their prioritization helps you control exactly which frames appear in your analysis. This guide examines the source code implementation in [`skills/watch/scripts/frames.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/frames.py) to explain the parsing logic, extraction pipeline, and frame priority rules.

## Timestamp Parsing Logic in [`frames.py`](https://github.com/bradautomates/claude-video/blob/main/frames.py)

The core parsing functionality resides in [`skills/watch/scripts/frames.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/frames.py), where the `parse_timestamps()` function converts raw user input into a clean list of seconds.

### The `parse_timestamps()` Function

According to the source code at lines 95-103, `parse_timestamps()` processes the input string through several normalization steps:

- The raw string is split on commas
- Each token is stripped of surrounding whitespace
- Empty tokens are ignored
- Each non-empty token is passed to `parse_time()` for format conversion

The resulting float values are collected, de-duplicated using `set()`, and sorted into ascending order.

### Supported Time Formats

The underlying `parse_time()` function (lines 55-72) accepts three distinct formats:

- **SS** – Seconds only (e.g., `30`)
- **MM:SS** – Minutes and seconds (e.g., `1:05`)
- **HH:MM:SS** – Hours, minutes, and seconds (e.g., `1:30:45`)

All formats optionally support fractional seconds for precise frame extraction.

Example transformation:

```

"30,1:05,90" → [30.0, 65.0, 90.0]
" 90 , 30, 30 " → [30.0, 90.0]

```

## Cue Frame Extraction and Sampling

Once parsed, the timestamp list flows into `extract_at_timestamps()` at lines 124-132, which manages the actual frame extraction pipeline.

### Filtering by Focus Window

The function first validates each timestamp against the current focus window (`[start, end]`). Timestamps falling outside this window are dropped from the candidate list, ensuring only relevant frames are processed.

### Even Sampling When Over Limit

If a `max_frames` limit is configured and the surviving timestamp count exceeds this budget, the system applies `_even_indices()` (lines 84-92) to perform even sampling. This algorithm preserves the first and last timestamps while distributing selections evenly across the time range. Each retained timestamp generates exactly one frame extracted via ffmpeg and saved as `cue_*.jpg`.

## Prioritization of Cue Frames Over Automatic Selection

Cue frames receive special treatment in the frame selection hierarchy, guaranteeing their inclusion regardless of other constraints.

### Merge Logic in `merge_frames()`

The `merge_frames()` function (lines 12-20) combines outputs from the automatic detail engine (scene/keyframe/uniform sampling) with the cue-frame engine. Because the implementation concatenates the cue list before sorting chronologically, **cue frames are always kept** and never discarded by later capping logic applied to the detail engine. This architectural choice ensures explicit user requests take precedence over algorithmic selections.

### Interaction with `--detail transcript` Mode

When using `--detail transcript` alongside `--timestamps`, the behavior shifts significantly. As implemented in [`skills/watch/scripts/watch.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/watch.py) at lines 107-112, the transcript-detail path intentionally returns **only the cue frames**, skipping the normal detail engine entirely. This creates a focused analysis mode where you receive exactly the frames you specified plus transcript data, without additional scene or keyframe sampling.

## Practical Usage Examples

Basic timestamp extraction:

```bash

# Grab frames at three explicit moments (30 s, 1 min 5 s, 90 s)

claude-video watch myvideo.mp4 --timestamps 30,1:05,90

```

Programmatic access:

```python
from skills.watch.scripts.frames import parse_timestamps, extract_at_timestamps
from pathlib import Path

# Parse a user-supplied timestamps string

seconds = parse_timestamps("30, 1:05, 90")

# → [30.0, 65.0, 90.0]

# Extract one frame per timestamp (saving to ./out)

frames, meta = extract_at_timestamps(
    video_path="myvideo.mp4",
    out_dir=Path("./out"),
    timestamps=seconds,
    resolution=512,
    max_frames=None,
)
print(meta)

# {'engine': 'timestamps', 'candidate_count': 3,

#  'selected_count': 3, 'dropped_out_of_window': 0, 'fallback': False}

```

Transcript-only mode with cues:

```bash
claude-video watch myvideo.mp4 --detail transcript --timestamps 4:32,7:10,9:55

# Output: cue frames only – no additional scene/keyframe frames.

```

## Summary

- **Parsing pipeline**: `parse_timestamps()` splits on commas, cleans whitespace, and converts to sorted unique seconds using `parse_time()` for SS, MM:SS, or HH:MM:SS formats.
- **Extraction logic**: `extract_at_timestamps()` filters by focus window, applies even sampling if over budget, and generates `cue_*.jpg` files via ffmpeg.
- **Priority guarantee**: Cue frames are concatenated first in `merge_frames()`, ensuring they survive any frame budget caps applied to automatic selection engines.
- **Transcript mode**: Combining `--detail transcript` with `--timestamps` returns only cue frames, bypassing scene and keyframe analysis entirely.

## Frequently Asked Questions

### What time formats does `--timestamps` accept?

The `parse_time()` function in [`skills/watch/scripts/frames.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/frames.py) accepts three formats: raw seconds (`30`), minutes and seconds (`1:05`), or hours, minutes, and seconds (`1:30:45`). All formats support optional fractional seconds for sub-second precision.

### How does claude-video handle duplicate or out-of-order timestamps?

The system automatically de-duplicates timestamps using `set()` and sorts them numerically before extraction. Whitespace around entries is stripped, and empty tokens are ignored, so inputs like `" 90 , 30, 30 "` normalize to `[30.0, 90.0]`.

### Do cue frames count against the `max_frames` budget?

During the initial extraction phase, yes—`extract_at_timestamps()` applies `_even_indices()` to downsample if you provide more timestamps than `max_frames` allows. However, once the cue list is generated, these frames are protected from any subsequent capping logic when merged with automatic selections.

### What happens when I combine `--timestamps` with `--detail transcript`?

As implemented in [`skills/watch/scripts/watch.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/watch.py) lines 107-112, this combination triggers a cue-only mode that returns exclusively the frames at your specified timestamps. The normal detail engine (scene/keyframe/uniform sampling) is bypassed entirely, giving you precise visual control alongside transcript analysis.