# Video Tagging

> Tag, bucket, and search video clips in Video Review OS. Use when working with tags.json, content buckets, event/performer/venue tags, per-clip topics, the shared clip library, cross-project search, or when a user asks to find footage by what it shows or what was said. Also use when correcting a wrong tag or explaining how a bucket was chosen.

- Skill: `cgallic/video-tagging` (Agent Skill)
- Install (CLI): `npx skillmds@latest add cgallic/video-tagging`
- Raw SKILL.md: https://api.skillmd.com/api/skills/cgallic/video-tagging/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- License: MIT
- Author: cgallic (https://skillmd.com/u/cgallic)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/cgallic/video-tagging

---


# Tagging and finding footage

`tags.json` (schema `video_review_os.tags.v2`) makes a raw library findable. v2 is
strictly additive over v1: the source-level `tags` record keeps every key it always had
and gains a `visual` summary, joined by a new per-clip `clips` list.

```bash
video-review-os tag <project>              # writes tags.json
video-review-os library speech-search "…"  # find a spoken phrase across every project
```

## Source level

`event_type`, `performer`, `track`, `venue`, `energy`, `has_vocal`, `orientation`,
`usable_vertical`, `duration`, `quality_flags`, and a first-class `bucket`. A clip never
leaves the tagger without a bucket — the default is `broll_trending`.

Bucket logic is deliberately simple and inspectable:

- identified performer + vocal + event type → `real_gfa` (the high-craft lane)
- vocal + second-person address ("you", "here's how", "if you") → `direct_camera`
- everything else → `config.tagging.default_bucket`

Populate `[tagging] roster` and `venues` with the names you actually shoot; matching is
whole-word against filename plus transcript. An empty roster is why `performer` is null.

## Clip level

Each entry in `clips` carries `topics` (frequent meaningful words from that clip's text),
`has_speech`, the visual attributes perception found, `reframe_needed`, and
`quality_flags`. With no `perception.json` the visual fields are all `unknown` and
everything else still works — perception is optional, not a prerequisite.

`tags["visual"]` rolls the per-clip readings into a source-level summary. `unknown` never
wins a vote there: a source with two known readings and eight unknowns describes itself by
the two.

## When a tag is wrong

Correct it in the `tag_overrides.json` sidecar, keyed by `approval_key` — never by editing
`tags.json`, which is regenerated. Overrides keyed by content hash survive re-tagging;
overrides keyed by position do not, which is why the sidecar shape is what it is.

## Using a model for tagging

Same contract as every other stage — a provider name in config, no vendor in the code:

```toml
[tagging]
provider = "generic-http"
hosted_endpoint_env = "VIDEO_REVIEW_TAG_ENDPOINT"
hosted_api_key_env  = "VIDEO_REVIEW_TAG_API_KEY"
```

The response is sanitized: unknown buckets and orientations fall back to the deterministic
value, so a hostile or confused endpoint cannot introduce a bucket the rest of the system
does not understand. Verify this holds if you extend the schema — every new field needs a
sanitize rule and a test.

