Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,21 @@ On Debian/Ubuntu:
sudo apt install yt-dlp ffmpeg jq python3 curl
```

### Optional install flags

```bash
./install.sh --with-skill # also drop SKILL.md into ~/.claude/skills/watch-cli/
./install.sh --with-mcp # print the npm install hint for the MCP stdio server
```

- `--with-skill` copies the portable `SKILL.md` into `~/.claude/skills/watch-cli/`
so Claude Code picks up watch-cli as a skill on next start. The same file
works in OpenClaw and hermes-agent — see [`SKILL.md`](SKILL.md).
- `--with-mcp` prints the manual install line for [`@sonpiaz/watch-cli-mcp`](mcp-server/),
the MCP stdio server that exposes watch-cli to Claude Desktop, Cursor, Cline,
Continue.dev, Windsurf, Zed, and any other MCP-capable client. The flag will
auto-install once the package is published to npm.

---

## Setup
Expand Down
74 changes: 74 additions & 0 deletions SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
---
name: watch-cli
description: "Watch any social video → get an architecture diagram, working component, runnable notebook, or step-by-step cheat sheet — automatically."
homepage: https://github.com/sonpiaz/watch-cli
metadata:
openclaw:
emoji: ""
requires:
bins:
- watch
install:
- id: curl-install
kind: shell
command: "curl -fsSL https://raw.githubusercontent.com/sonpiaz/watch-cli/main/install.sh | bash"
bins:
- watch
label: "Install watch-cli (curl)"
---

Watch any social video → get an architecture diagram, working component, runnable notebook, or step-by-step cheat sheet — automatically.

watch-cli is a thin orchestrator that downloads any social video, extracts evenly-spaced frames, and transcribes the audio. The output is a single labeled block (or one-line JSON) designed for an LLM to read frames as images and transcript as text. The agent supplies the prompt; watch-cli supplies the raw materials.

## When to invoke

Reach for `watch` whenever the user gives you a video URL and wants you to do something with what's in it.

- The user pastes a video URL with no verb. Ask one clarifying question ("summarize, implement, clone the UI, extract the architecture, or something else?"), then run `watch`.
- The user asks to "summarize", "explain", or "walk me through" content at a video URL.
- The user asks to "implement", "clone", "build", or "replicate" what is on screen in a video.
- The user asks to "extract architecture from", "diagram", or "turn this paper talk into code" at a video URL.

Supported platforms: YouTube, X / Twitter, LinkedIn, TikTok, Vimeo, Reddit, Facebook. Login-walled sources fall back to the user's signed-in browser cookies automatically.

## What you get back

The `watch` output gives you the raw materials to map to five concrete artifacts. Match the user's intent to one of them.

A coding walkthrough becomes working project files: read the frames for file names, exact code, and dependencies; read the transcript for intent and rationale; emit the final state, not the intermediate edits.

A system architecture talk becomes an interactive architecture diagram: a single self-contained HTML page with actors, surfaces, APIs, and clickable named flows that highlight the path through the system.

A UI or motion demo becomes a working React component: one paste-ready `.tsx` file that captures the feel and the single interaction that makes the UI special, not a pixel-perfect screenshot.

A paper or research talk becomes a runnable notebook: one `.ipynb` implementing the core method on a toy dataset that runs end-to-end on a free Colab T4.

A long tutorial becomes a step-by-step cheat sheet: numbered steps with copy-pasteable commands, video timestamps, verification per step, and only the troubleshooting the speaker actually discussed.

Five copy-paste prompt templates live in [`prompts/`](https://github.com/sonpiaz/watch-cli/tree/main/prompts). Pick the one that matches the user's intent.

## Parse rules

`watch` emits a versioned, agent-shaped payload. Both formats are documented in [`docs/output-schema.md`](https://github.com/sonpiaz/watch-cli/blob/main/docs/output-schema.md) and conform to the v1 contract — append-only, no renames, no type changes within v1.

- **Preferred: JSON mode.** `watch <url> --format json` emits one UTF-8 JSON object on stdout terminated by a newline. Parse it with a real JSON parser, switch on `obj.version`, read `obj.video_path`, `obj.duration_sec`, `obj.frame_paths` (array of absolute JPG paths, earliest-in-video first), `obj.transcript` (string or `null`), and `obj.exit_code`. Field reference is the single source of truth in `docs/output-schema.md`.
- **Fallback: text mode.** Some agent hosts (Claude Code does this today) capture stdout as a free-text block. The leading line `WATCH_OUTPUT_VERSION: 1` is the version signal; everything below is labeled blocks (`VIDEO:`, `DURATION:`, `FRAMES:`, `TRANSCRIPT:`, `EXIT:`) per the same doc.
- **Read frames as images, transcript as text.** Each path under `FRAMES:` (or each string in `frame_paths`) is an absolute path to a JPG on disk. Pass the path to the host's image-reading primitive. The transcript is plain UTF-8 text — no decoding needed.
- **Exit-code behavior** is documented in [`docs/exit-codes.md`](https://github.com/sonpiaz/watch-cli/blob/main/docs/exit-codes.md). The partial-success case is the one to remember: on `exit 4` the frames are populated and the transcript is `null` — branch on the exit code and fall through to a frames-only consumption path instead of failing the run.

## Invocation

```bash
watch <url> [frame-count]
```

Default frame count is 8. For a fast-cut or dense UI demo, double it. For a multi-hour conference talk, bump to 24–32. The CLI does not cap; agent hosts typically prefer ≤ 32.

## Anti-patterns

- Do not parse stderr. Progress lines on stderr (`[watch] downloading …`) are not part of the contract and change between releases. Programmatic consumers ignore stderr.
- Do not parse the filename of a frame to infer its position. Filenames are implementation detail; the ordering of `frame_paths` is the contract.
- Do not hard-fail on every non-zero exit. `exit 4` is recoverable partial success — frames populated, transcript `null`. Branch on `exit_code` before parsing.
- Do not surface API keys or environment variable names in chat. `KYMA_API_KEY` setup lives in the README.
- Do not embed the locked pitch into a longer marketing paragraph. The description line above is the source of truth; reuse it verbatim where the host shows skill metadata.
57 changes: 57 additions & 0 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,56 @@
# curl -fsSL https://raw.githubusercontent.com/sonpiaz/watch-cli/main/install.sh | bash
# or, from a clone:
# ./install.sh
#
# Flags:
# --with-skill After install, drop SKILL.md into ~/.claude/skills/watch-cli/
# so Claude Code picks up the watch-cli skill on next start.
# --with-mcp Print the manual install hint for the MCP stdio server
# (@sonpiaz/watch-cli-mcp on npm — not auto-installed yet).
# --help, -h Show this help and exit.

set -euo pipefail

REPO_URL="https://github.com/sonpiaz/watch-cli"
INSTALL_DIR="${WATCH_CLI_HOME:-$HOME/.watch-cli}"
BIN_LINK_DIR="${WATCH_CLI_BIN:-$HOME/.local/bin}"
CLAUDE_SKILLS_DIR="${HOME}/.claude/skills"

WITH_SKILL=0
WITH_MCP=0

red() { printf "\033[31m%s\033[0m\n" "$*"; }
green() { printf "\033[32m%s\033[0m\n" "$*"; }
yellow() { printf "\033[33m%s\033[0m\n" "$*"; }
dim() { printf "\033[2m%s\033[0m\n" "$*"; }

usage() {
cat <<'EOF'
watch-cli installer

Usage:
curl -fsSL https://raw.githubusercontent.com/sonpiaz/watch-cli/main/install.sh | bash
./install.sh [--with-skill] [--with-mcp]

Flags:
--with-skill After install, copy SKILL.md into ~/.claude/skills/watch-cli/
so Claude Code picks up the watch-cli skill on next start.
--with-mcp Print the manual install hint for the MCP stdio server
(@sonpiaz/watch-cli-mcp on npm — not auto-installed yet).
-h, --help Show this help and exit.
EOF
}

# ── Parse args ──
while (($# > 0)); do
case "$1" in
--with-skill) WITH_SKILL=1; shift ;;
--with-mcp) WITH_MCP=1; shift ;;
-h|--help) usage; exit 0 ;;
*) red "Unknown flag: $1"; echo; usage; exit 64 ;;
esac
done

echo "watch-cli installer"
echo "==================="

Expand Down Expand Up @@ -67,6 +105,25 @@ if [[ ":$PATH:" != *":$BIN_LINK_DIR:"* ]]; then
echo
fi

# ── Optional: drop portable SKILL.md into ~/.claude/skills/watch-cli/ ──
if (( WITH_SKILL )); then
if [[ -f "$INSTALL_DIR/SKILL.md" ]]; then
mkdir -p "$CLAUDE_SKILLS_DIR/watch-cli"
cp "$INSTALL_DIR/SKILL.md" "$CLAUDE_SKILLS_DIR/watch-cli/SKILL.md"
green "✓ Installed SKILL.md → $CLAUDE_SKILLS_DIR/watch-cli/SKILL.md"
else
yellow "⚠ --with-skill: $INSTALL_DIR/SKILL.md not found; skipped."
fi
fi

# ── Optional: MCP stdio server hint ──
if (( WITH_MCP )); then
echo
yellow "MCP server install will be available once @sonpiaz/watch-cli-mcp is published to npm — install manually for now:"
echo " npm install -g @sonpiaz/watch-cli-mcp"
echo
fi

# ── Env file scaffold ──
ENV_DIR="$HOME/.config/watch-cli"
ENV_FILE="$ENV_DIR/env"
Expand Down
4 changes: 4 additions & 0 deletions mcp-server/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules/
dist/
*.log
.DS_Store
137 changes: 137 additions & 0 deletions mcp-server/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# @sonpiaz/watch-cli-mcp

MCP (Model Context Protocol) stdio server that exposes [watch-cli](https://github.com/sonpiaz/watch-cli) as a callable tool.

> Watch any social video → get an architecture diagram, working component, runnable notebook, or step-by-step cheat sheet — automatically.

A single MCP server reaches every MCP-capable agent runtime — Claude Desktop, Claude Code, Cursor, OpenClaw, hermes-agent, Cline, Continue.dev, Windsurf, Zed, Codex, Kiro, VS Code Copilot — without per-IDE plugin work. This package wraps `watch-cli` so any of them can call it through one channel.

## Prerequisites

- Node.js >= 18.
- The `watch` CLI installed and on `PATH`. Install with:

```bash
curl -fsSL https://raw.githubusercontent.com/sonpiaz/watch-cli/main/install.sh | bash
```

The MCP server shells out to `watch`; it does not bundle the CLI.

## Install

```bash
npm install -g @sonpiaz/watch-cli-mcp
```

Or run on demand via `npx`:

```bash
npx -y @sonpiaz/watch-cli-mcp
```

The binary is `watch-cli-mcp`. It reads JSON-RPC on stdin, writes JSON-RPC on stdout, and logs to stderr.

## Tool

One tool is registered: `watch`.

**Input schema:**

```json
{
"type": "object",
"properties": {
"url": {
"type": "string",
"format": "uri",
"description": "A social video URL. Supported: YouTube, X / Twitter, LinkedIn, TikTok, Vimeo, Reddit, Facebook."
},
"frames": {
"type": "integer",
"minimum": 1,
"maximum": 64,
"description": "Number of evenly-spaced frames to extract. Default 8."
}
},
"required": ["url"],
"additionalProperties": false
}
```

**Output:** the v1 JSON object from [`docs/output-schema.md`](https://github.com/sonpiaz/watch-cli/blob/main/docs/output-schema.md), passed through verbatim. Read the schema for the field reference.

## Error mapping

| CLI exit | MCP response |
|---|---|
| `0` | Tool result with the v1 JSON as `content[0].text`. |
| `2` | `InternalError`, message includes `tag=missing-dep:<bin>`. |
| `3` `download-auth` / `download-region` | `InvalidParams`, message includes the tag — caller can recover with cookies or a different URL. |
| `3` `download-network` / `download-other` | `InternalError`, message includes the tag. |
| `4` (partial success) | Tool result with `isError: false`. Frames populated, transcript `null`, `exit_code: 4` in the JSON payload. Caller branches on `obj.exit_code === 4`. |
| `64` | `InvalidParams`, message includes `tag=usage-error`. |
| `1` / other | `InternalError`, message includes the CLI stderr tail (≤ 1 KB). |

Tags always ride in the MCP error `message` field so callers can grep for the same `tag=...` token they would see in CLI stderr.

## Client configuration

### Claude Desktop

Config path:

- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
- Linux: `~/.config/Claude/claude_desktop_config.json`

Merge into the existing `mcpServers` object:

```json
{
"mcpServers": {
"watch-cli": {
"command": "npx",
"args": ["-y", "@sonpiaz/watch-cli-mcp"]
}
}
}
```

Restart Claude Desktop after editing.

### Cursor

Config path: `.cursor/mcp.json` (project-scoped) or `~/.cursor/mcp.json` (user-global). Same `mcpServers` object shape as Claude Desktop:

```json
{
"mcpServers": {
"watch-cli": {
"command": "npx",
"args": ["-y", "@sonpiaz/watch-cli-mcp"]
}
}
}
```

### hermes-agent

Config path: `optional-skills/mcp.json` inside the hermes-agent install, or `~/.hermes-agent/mcp.json` user-global. Same `mcpServers` shape as above.

### Other MCP clients

Any MCP-capable agent that accepts an `npx` command will work with the snippet above. Substitute the client's config path; the `command` / `args` pair is portable.

## Build from source

```bash
git clone https://github.com/sonpiaz/watch-cli
cd watch-cli/mcp-server
npm install
npm run build
node dist/index.js
```

## License

MIT. © 2026 Son Piaz.
Loading
Loading