# taoufik123-collab/claude-watch architecture

> Architecture diagram of the GitHub repository taoufik123-collab/claude-watch, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-16). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/taoufik123-collab/claude-watch
- Repository: https://github.com/taoufik123-collab/claude-watch

## Overview

1. **This repo is a local Claude skill/plugin, not a web service.**  
   The architecture is centered on shelling out from Claude Code / claude.ai / Codex to local Python scripts. There is no persistent backend; each `/watch` run is an isolated pipeline execution on the user’s machine.

2. **Three packaging surfaces share one core skill contract.**  
   `SKILL.md` is the common entrypoint text. The repo also includes `.claude-plugin/` and `.codex-plugin/` manifests for platform-specific installation, plus `commands/watch.md` for the command surface. The same underlying behavior is packaged differently for Claude Code, claude.ai skills, and Codex skills.

3. **The main orchestration boundary is `scripts/watch.py`.**  
   This is the top-level driver that coordinates the workflow: resolve input, download or inspect the media, extract frames, get a transcript, and assemble output for Claude. It is the central integration point between all other subsystems.

4. **Media acquisition is handled by `scripts/download.py` via `yt-dlp`.**  
   This layer is responsible for both remote URLs and local-file handling. For URLs it downloads into a working directory; for local files it probes in place. This is the boundary between “user input” and “analysis-ready media.”

5. **Visual analysis is a dedicated ffmpeg subsystem in `scripts/frames.py`.**  
   The repo’s key architectural differentiation is that frames are not sampled uniformly. Instead, `frames.py` uses scene-change extraction plus duration-aware auto-scaling, with hard caps on fps and total frame count. This keeps image-token cost bounded and makes the output structure depend on content cuts, not runtime length.

6. **Focused opening analysis is a separate visual/audio path in `scripts/hook.py` and `scripts/pacing.py`.**  
   The “0–10s hook microscope” is treated as a special case: denser frame extraction for the opening segment plus transcript timing support. `pacing.py` suggests a dedicated concern for rate/budget calculation, especially for the opening attention-critical window.

7. **Transcription is a two-stage subsystem in `scripts/transcribe.py` and `scripts/whisper.py`.**  
   The first preference is native captions retrieved through `yt-dlp`. If captions are unavailable, the pipeline falls back to Whisper transcription, with `whisper.py` acting as the service client boundary. The repo supports Groq and OpenAI backends, with Groq preferred for cost/speed. `--no-whisper` cleanly disables this branch.

8. **Structured output is generated by `scripts/report.py`.**  
   Rather than producing only freeform text, the repo builds a fixed-schema `report.md` with sections like TL;DR, key moments, hook breakdown, editorial profile, entities, concepts, and transcript. The `<!-- pending Claude fill: ... -->` markers indicate an intentional handoff between scripted extraction and Claude’s narrative synthesis.

9. **There is an optional Obsidian vault ingest path.**  
   The pipeline can stage watched-video notes into a vault under `raw/watched/<slug>/` and open them through the `obsidian://` scheme. This is gated by `WATCH_VAULT_DIR` or auto-detection of common vault locations, and it is designed to fail silently when no vault is present.

10. **Environment/bootstrap concerns are isolated in `scripts/setup.py` and the hook checks.**  
    First-run setup validates `ffmpeg`, `yt-dlp`, and Whisper API credentials, and may install dependencies on macOS via Homebrew. `hooks/hooks.json` and `hooks/scripts/check-setup.sh` define a Claude Code SessionStart hook that keeps this preflight out of the main analysis flow.

11. **The repository includes a release/build packaging layer.**  
    `scripts/build-skill.sh` builds the distributable `dist/watch.skill` bundle for claude.ai. `.github/workflows/release.yml` automates that build on tag push and attaches the artifact to releases. This is the only CI-style infrastructure in the repo.

12. **Testing is focused on the pure logic, not the external tools.**  
    `scripts/tests/` covers frame-scene behavior, pacing, and report generation. That suggests the repo’s most important correctness boundaries are its budgeting heuristics and report structure, while the actual `ffmpeg`/`yt-dlp`/Whisper calls are treated as integration dependencies.

13. **Overall data flow is linear with one optional branch.**  
    Input video → download/probe → frame extraction → transcript acquisition → report assembly → optional Obsidian save/open → Claude reads media and finalizes response. The only major conditional branch is transcription fallback from captions to Whisper, and the optional vault ingest at the end.

Main entry points: [`scripts/watch.py`](https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/watch.py) (watch.py), [`SKILL.md`](https://github.com/taoufik123-collab/claude-watch/blob/main/SKILL.md) (SKILL.md), [`scripts/frames.py`](https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/frames.py) (frames.py), [`scripts/report.py`](https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/report.py) (report.py)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_packaging["Packaging surfaces"]
  node_skill_md["SKILL.md<br/>skill contract<br/>[SKILL.md]"]
  node_claude_plugin[".claude-plugin<br/>Claude packaging<br/>[plugin.json]"]
  node_codex_plugin[".codex-plugin<br/>Codex packaging<br/>[plugin.json]"]
  node_watch_command["watch.md<br/>command surface<br/>[watch.md]"]
end

subgraph group_pipeline["Analysis pipeline"]
  node_watch_py["watch.py<br/>orchestrator<br/>[watch.py]"]
  node_download_py["download.py<br/>media ingest<br/>[download.py]"]
end

subgraph group_analysis["Media analysis"]
  node_frames_py["frames.py<br/>frame extraction<br/>[frames.py]"]
  node_hook_py["hook.py<br/>opening analysis<br/>[hook.py]"]
  node_pacing_py["pacing.py<br/>budgeting<br/>[pacing.py]"]
  node_transcribe_py["transcribe.py<br/>transcription router<br/>[transcribe.py]"]
  node_whisper_py["whisper.py<br/>Whisper client<br/>[whisper.py]"]
end

subgraph group_output["Output and vault"]
  node_report_py["report.py<br/>report assembly<br/>[report.py]"]
  node_obsidian_path[("Vault ingest<br/>optional export")]
end

subgraph group_ops["Operations"]
  node_setup_py["setup.py<br/>bootstrap<br/>[setup.py]"]
  node_hook_checks["hooks<br/>session start hook<br/>[hooks.json]"]
  node_build_script["build-skill.sh<br/>build packager<br/>[build-skill.sh]"]
  node_release_workflow["release.yml<br/>release automation<br/>[release.yml]"]
end

subgraph group_tests["Tests"]
  node_test_frames["frame tests<br/>unit tests"]
  node_test_pacing["pacing tests<br/>unit tests<br/>[test_pacing.py]"]
  node_test_report["report tests<br/>unit tests<br/>[test_report.py]"]
end

node_skill_md -->|"shared contract"| node_claude_plugin
node_skill_md -->|"shared contract"| node_codex_plugin
node_skill_md -->|"command entry"| node_watch_command
node_watch_command -->|"invokes"| node_watch_py
node_watch_py -->|"acquire media"| node_download_py
node_watch_py -->|"extract frames"| node_frames_py
node_watch_py -->|"get transcript"| node_transcribe_py
node_watch_py -->|"special case"| node_hook_py
node_watch_py -->|"assemble output"| node_report_py
node_hook_py -->|"budget window"| node_pacing_py
node_transcribe_py -->|"fallback"| node_whisper_py
node_whisper_py -.->|"credentials"| node_setup_py
node_frames_py -->|"budget frames"| node_pacing_py
node_report_py -.->|"optional save"| node_obsidian_path
node_setup_py -->|"preflight"| node_hook_checks
node_build_script -->|"automates"| node_release_workflow
node_test_frames -.->|"verifies"| node_frames_py
node_test_pacing -.->|"verifies"| node_pacing_py
node_test_report -.->|"verifies"| node_report_py

click node_skill_md "https://github.com/taoufik123-collab/claude-watch/blob/main/SKILL.md"
click node_claude_plugin "https://github.com/taoufik123-collab/claude-watch/blob/main/.claude-plugin/plugin.json"
click node_codex_plugin "https://github.com/taoufik123-collab/claude-watch/blob/main/.codex-plugin/plugin.json"
click node_watch_command "https://github.com/taoufik123-collab/claude-watch/blob/main/commands/watch.md"
click node_watch_py "https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/watch.py"
click node_download_py "https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/download.py"
click node_frames_py "https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/frames.py"
click node_hook_py "https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/hook.py"
click node_pacing_py "https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/pacing.py"
click node_transcribe_py "https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/transcribe.py"
click node_whisper_py "https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/whisper.py"
click node_report_py "https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/report.py"
click node_setup_py "https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/setup.py"
click node_hook_checks "https://github.com/taoufik123-collab/claude-watch/blob/main/hooks/hooks.json"
click node_build_script "https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/build-skill.sh"
click node_release_workflow "https://github.com/taoufik123-collab/claude-watch/blob/main/.github/workflows/release.yml"
click node_test_frames "https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/tests/test_frames_scene.py"
click node_test_pacing "https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/tests/test_pacing.py"
click node_test_report "https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/tests/test_report.py"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_skill_md,node_claude_plugin,node_codex_plugin,node_watch_command toneBlue
class node_watch_py,node_download_py toneAmber
class node_frames_py,node_hook_py,node_pacing_py,node_transcribe_py,node_whisper_py toneMint
class node_report_py,node_obsidian_path toneRose
class node_setup_py,node_hook_checks,node_build_script,node_release_workflow toneIndigo
class node_test_frames,node_test_pacing,node_test_report toneTeal
```

## Components

### Packaging surfaces

Entry points and install/build surfaces for Claude Code, claude.ai, and Codex.

- [SKILL.md](https://github.com/taoufik123-collab/claude-watch/blob/main/SKILL.md): skill contract · Common skill entrypoint text shared across packaging surfaces. · `SKILL.md`
- [.claude-plugin](https://github.com/taoufik123-collab/claude-watch/blob/main/.claude-plugin/plugin.json): Claude packaging · Claude Code / claude.ai plugin manifest surface. · `.claude-plugin/plugin.json`
- [.codex-plugin](https://github.com/taoufik123-collab/claude-watch/blob/main/.codex-plugin/plugin.json): Codex packaging · Codex skill packaging surface. · `.codex-plugin/plugin.json`
- [watch.md](https://github.com/taoufik123-collab/claude-watch/blob/main/commands/watch.md): command surface · Command-facing wrapper for the watch workflow. · `commands/watch.md`

### Analysis pipeline

The local shell-driven workflow that downloads media, extracts frames, transcribes audio, and assembles output.

- [watch.py](https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/watch.py): orchestrator · Top-level driver for the full watch pipeline. · `scripts/watch.py`
- [download.py](https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/download.py): media ingest · Resolves URLs or local files and prepares media for analysis. · `scripts/download.py`

### Media analysis

Visual and audio extraction subsystems used by the watch workflow.

- [frames.py](https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/frames.py): frame extraction · Scene-aware frame sampling with duration-aware scaling and token-budget caps. · `scripts/frames.py`
- [hook.py](https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/hook.py): opening analysis · Specialized 0–10s hook extraction path. · `scripts/hook.py`
- [pacing.py](https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/pacing.py): budgeting · Rate and budget calculations for analysis windows. · `scripts/pacing.py`
- [transcribe.py](https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/transcribe.py): transcription router · Chooses native captions first, then Whisper fallback when needed. · `scripts/transcribe.py`
- [whisper.py](https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/whisper.py): Whisper client · Backend boundary for Groq and OpenAI Whisper transcription. · `scripts/whisper.py`

### Output and vault

Report generation and optional Obsidian vault staging.

- [report.py](https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/report.py): report assembly · Builds the structured report and Claude handoff markers. · `scripts/report.py`
- **Vault ingest**: optional export · Stages notes into an Obsidian vault and opens them via obsidian:// when available.

### Operations

Setup checks, hooks, build, and release automation.

- [setup.py](https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/setup.py): bootstrap · Preflight checks for ffmpeg, yt-dlp, Whisper credentials, and local setup. · `scripts/setup.py`
- [hooks](https://github.com/taoufik123-collab/claude-watch/blob/main/hooks/hooks.json): session start hook · Claude Code SessionStart checks that keep setup validation outside the main flow. · `hooks/hooks.json`
- [build-skill.sh](https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/build-skill.sh): build packager · Creates the distributable claude.ai skill bundle. · `scripts/build-skill.sh`
- [release.yml](https://github.com/taoufik123-collab/claude-watch/blob/main/.github/workflows/release.yml): release automation · Builds and attaches the skill artifact on tag push. · `.github/workflows/release.yml`

### Tests

Focused checks for the core pure logic.

- [frame tests](https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/tests/test_frames_scene.py): unit tests · Checks scene-extraction behavior. · `scripts/tests/test_frames_scene.py`
- [pacing tests](https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/tests/test_pacing.py): unit tests · Checks pacing and budgeting logic. · `scripts/tests/test_pacing.py`
- [report tests](https://github.com/taoufik123-collab/claude-watch/blob/main/scripts/tests/test_report.py): unit tests · Checks report structure and generation rules. · `scripts/tests/test_report.py`

## Connections

- SKILL.md → .claude-plugin: shared contract · The same core skill content is packaged for Claude surfaces.
- SKILL.md → .codex-plugin: shared contract · The same core skill content is packaged for Codex.
- SKILL.md → watch.md: command entry · The command surface exposes the watch workflow.
- watch.md → watch.py: invokes · Command wrapper hands off to the orchestrator.
- watch.py → download.py: acquire media · Resolves remote or local media before analysis.
- watch.py → frames.py: extract frames · Feeds prepared media into frame sampling.
- watch.py → transcribe.py: get transcript · Obtains captions or Whisper output for the video.
- watch.py → hook.py: special case · Runs the denser opening-segment path when needed.
- watch.py → report.py: assemble output · Collects extracted data into the structured report.
- hook.py → pacing.py: budget window · Uses pacing logic for the attention-critical opening window.
- transcribe.py → whisper.py: fallback · Falls back to Whisper backends when captions are unavailable.
- whisper.py → setup.py: credentials · Whisper usage depends on preflighted local setup and API access.
- frames.py → pacing.py: budget frames · Scene-aware extraction is constrained by rate and token budgets.
- report.py → Vault ingest: optional save · Report output can be staged into a vault for later review.
- setup.py → hooks: preflight · Setup validation is also enforced at session start by hooks.
- build-skill.sh → release.yml: automates · Release workflow runs the packaging step on tagged releases.
- frame tests → frames.py: verifies · Tests the scene-extraction boundary.
- pacing tests → pacing.py: verifies · Tests the budgeting and timing heuristics.
- report tests → report.py: verifies · Tests the structured report schema and sections.
