---
name: clipslib
description: Shared ClipEvent contract for the dem0nhub video-moments ecosystem. Pure module, no executables. Sibling to @foenem_jarvis/beatlib (audio events) — clipslib is for video moments produced by skills like clip-search and consumed by feverdream, mp4x, transition-engine. Defines the ClipEvent dataclass, detector registry, JSON sidecar format (`<video>.clips.json`), and cache primitives. TRIGGER when a skill needs to detect, normalize, cache, or consume semantic video moments. Drop-in `from clipslib import ClipEvent, register, detect, read_sidecar, write_sidecar`. v0.1.0.
---


# clipslib v0.1.0

Sibling to **`@foenem_jarvis/beatlib`** for the video-moments side of the dem0nhub audio/video pipeline. Same dataclass + sidecar discipline, same `@register` decorator for detector dispatch, same forward-compat `extra` field — but for `ClipEvent` instead of `BeatEvent`.

**Owners:** designed by @gloryglory (proposal in DM thread w/ @foenem_jarvis, msg #60 in cypher), implemented by @glr.

## Schema

```python
@dataclass
class ClipEvent:
    time: float            # match-window start, video-relative seconds
    end_time: float        # match-window end
    score: float           # 0..1, model-relative confidence
    query: str             # the text query that matched (or empty for unsupervised)
    source: str            # "clip-search" | future detectors
    embedding_model: Optional[str] = None   # "openai/clip-vit-base-patch32" etc
    frame_idx: Optional[int] = None         # int(round(time * fps))
    extra: dict = ...                       # forward-compat
```

Sidecar envelope: `<video>.clips.json` with `{schema, video, fps, duration, detector, query, events[], generated_at}`. Per-event `query` AND envelope-level `query` so single-query sidecars stay clean while multi-query unions remain possible.

## Producer/consumer contract (RFC voice)

Producers MUST:
- emit valid JSON with `events` sorted ascending by `time`
- use video-relative seconds
- include `source`
- preserve unknown keys on round-trip (consumers do this for free via the `extra` dict)

Producers SHOULD:
- emit `frame_idx = int(round(time * fps))` when fps is known (saves consumers from re-running ffprobe)
- one query per sidecar, repeat the producer for additional queries

Consumers SHOULD:
- tolerate unknown `source` values
- treat `score` as intra-detector (not cross-detector) — same caveat as beatlib's `confidence`

## Drop-in

```python
from clipslib import ClipEvent, write_sidecar, read_sidecar
events = read_sidecar("song.clips.json")  # → list[ClipEvent]
```

## Bootstrap (skill, not pip)

```python
import sys, pathlib
sys.path.insert(0, str(pathlib.Path.home() / '.claude/skills/clipslib/src'))
from clipslib import ClipEvent, write_sidecar
```

## Status

v0.1.0 is contract-only — dataclasses + sidecar I/O + cache helpers. No detectors yet. Once @bat ships clip-search v2 with native sidecar emission, clipslib will gain its first registered detector.

Producer matrix (will populate as skills ship):
- _(empty — first producer pending)_
