{
  "markdown": "# yt-mem-ai — a local YouTube memory for your AI assistant\n\n<!-- mcp-name: io.github.dasein108/yt-mem-ai -->\n\nGive Claude, Codex, Cursor, or any MCP host the ability to **watch YouTube for\nyou**: transcribe videos, remember them, follow your subscriptions, and turn all\nof it into summaries, timestamped highlights, Q&A, digests, and video reels.\nEverything runs on your machine — no cloud service, no API key.\n\n![Installing the yt skills for Codex in one command](https://raw.githubusercontent.com/dasein108/yt-mem-ai/main/docs/demo/codex-install.gif)\n\n<p align=\"center\"><i>One command, two questions — here it's wiring the skills into Codex.</i></p>\n\n**Example** — *\"make a presentation from [this video](https://www.youtube.com/watch?v=96jN2OCOfLs)\"*\n(Andrej Karpathy: From Vibe Coding to Agentic Engineering, Sequoia, 30 min) →\n**[13 slides, PDF](https://github.com/dasein108/yt-mem-ai/blob/main/docs/demo/karpathy-agentic-engineering.pdf)**,\nevery quote timestamped from the transcript. Ingest to deck in one request.\n\n## Table of Contents\n\n* [Features](#features)\n* [How to install](#how-to-install)\n* [Getting Started](#getting-started)\n* [Usage](#usage)\n* [Examples](#examples)\n* [Configuration](#configuration)\n* [Under the hood](#under-the-hood)\n\n## Features\n\n* 🎧 **Transcribes any video** — YouTube captions when they exist (fast, any\n  language), offline Whisper when they don't.\n* 🧠 **Remembers what you watched** — every transcript is stored and indexed\n  locally, so your library stays searchable forever. Nothing leaves your machine.\n* 🔎 **Finds the moment** — ask \"what did that video say about X\" and get the\n  answer with a timestamp you can jump to.\n* 📡 **Follows your subscriptions** — picks up new uploads and turns the day into\n  one digest.\n* ✍️ **Your assistant does the writing** — summaries, highlights, Q&A, slide\n  decks, all in the video's own language, using the model you already pay for.\n* ❤️ **Learns your taste** — like or dislike videos and get recommendations from\n  your own library.\n* 🎬 **Makes media too** — clickable highlight docs, still frames, and rendered\n  supercut reels.\n* 🔌 **Works with your tools** — Claude Code, Claude Desktop, Codex, Cursor,\n  Antigravity, OpenClaw, Hermes: skills or MCP, your pick.\n\n## How to install\n\n### 1. Connect your assistant ⭐\n\n```bash\ncurl -LsSf https://raw.githubusercontent.com/dasein108/yt-mem-ai/main/install.sh | sh\n```\n\nAn interactive wizard opens. Pick what you want, tick your apps, press enter:\n\n```\nstep 1/2 — what (pick one)     step 2/2 — where (tick any)\n> Plugin  skills + CLI         [x] Claude Code    [ ] Claude Desktop\n  MCP     typed tools          [x] Codex          [ ] Cursor\n                               [ ] Antigravity    [ ] OpenClaw   [ ] Hermes\n```\n\n**Plugin** teaches your assistant to act on plain requests — *\"summarize this\nvideo\"*. **MCP** gives it a set of tools instead. Not sure? Start with Plugin;\nyou can run the wizard again for the other.\n\nIt installs everything it needs, ticks what you already have, and removes\nanything you untick (it shows a plan and asks first). Then **restart the app**\nand try: *summarize 'https://youtu.be/…'*.\n\nAlready know what you want? Skip the questions:\n\n```bash\ncurl -LsSf https://raw.githubusercontent.com/dasein108/yt-mem-ai/main/install.sh \\\n  | sh -s -- --plugin --claude-code --codex\ncurl -LsSf https://raw.githubusercontent.com/dasein108/yt-mem-ai/main/install.sh \\\n  | sh -s -- --mcp --claude-desktop --cursor\n```\n\nHosts: `--claude-code` `--claude-desktop` `--codex` `--cursor` `--antigravity`\n`--openclaw` `--hermes`, or `--all`. Full flag list and uninstall notes:\n[`integrations/README.md`](integrations/README.md). Rather have an agent do it?\nPaste [`integrations/PROMPT.md`](integrations/PROMPT.md) into any assistant.\n\n### 2. MCP by hand — one config entry, self-installing\n\nNo prior install needed: `uvx` fetches the package the first time the host\nlaunches the server, and keeps it cached afterwards. Drop this into your host's\nMCP config:\n\n```json\n{\n  \"mcpServers\": {\n    \"yt-mem-ai\": {\n      \"command\": \"uvx\",\n      \"args\": [\"--from\", \"yt-mem-ai[mcp]\", \"yt-ai-mcp\"]\n    }\n  }\n}\n```\n\nThat's the whole setup — no paths, no `env` block. Settings live in\n`~/.yt-mem-ai/config.env` and the agent can write them itself with the\n`config_set` tool (or you with `yt-ai config set`).\n\n| Host | Where that JSON goes |\n|---|---|\n| **Claude Desktop** | macOS `~/Library/Application Support/Claude/claude_desktop_config.json` · Windows `%APPDATA%\\Claude\\claude_desktop_config.json` — restart the app |\n| **Claude Code** | `claude mcp add -s user yt-mem-ai -- uvx --from 'yt-mem-ai[mcp]' yt-ai-mcp` |\n| **Cursor** | `~/.cursor/mcp.json` (reload Cursor) |\n| **Antigravity** | `~/.gemini/config/mcp_config.json` (restart) |\n| **Codex** | `~/.codex/config.toml` — TOML, see below (or `codex mcp add yt-mem-ai -- uvx --from 'yt-mem-ai[mcp]' yt-ai-mcp`) |\n| **OpenClaw** | `openclaw mcp add yt-mem-ai --command uvx --arg --from --arg 'yt-mem-ai[mcp]' --arg yt-ai-mcp` (or `~/.openclaw/openclaw.json` → `mcp.servers`) |\n| **Hermes** | `~/.hermes/config.yaml` under `mcp_servers:` — YAML, see below |\n\n```toml\n# ~/.codex/config.toml\n[mcp_servers.yt-mem-ai]\ncommand = \"uvx\"\nargs = [\"--from\", \"yt-mem-ai[mcp]\", \"yt-ai-mcp\"]\n```\n\n```yaml\n# ~/.hermes/config.yaml\nmcp_servers:\n  yt-mem-ai:\n    command: \"uvx\"\n    args: [\"--from\", \"yt-mem-ai[mcp]\", \"yt-ai-mcp\"]\n    enabled: true\n```\n\nRestart the app and the tools show up — see [Usage](#mcp-tools) for what they do.\n\n> **Nothing appeared, or the host timed out?** The first launch downloads\n> dependencies and can outlast the host's startup check. Run\n> `uvx --from 'yt-mem-ai[mcp]' yt-ai-mcp --help` once, then reopen the app. If\n> the host still can't start it, give it absolute paths — `uv tool install\n> 'yt-mem-ai[mcp]'` and use `which yt-ai-mcp` as `command` with `\"args\": []`\n> (GUI apps often don't see `~/.local/bin` on their `PATH`).\n\n### 3. Claude Desktop — skills (in the app)\n\nDesktop stores plugins on your Claude **account**, not on disk, so nothing can\ninstall them for you. It takes a minute in the app:\n\n> **Customize** (left sidebar) → **Plugins** → *Personal plugins* → **+** →\n> **Add marketplace** → **Add from a repository** →\n> `https://github.com/dasein108/yt-mem-ai` → **Add** → **Install** `yt-mem-ai`\n\nThen ask: *summarize 'https://youtu.be/…'*. Uninstall the same way. The same\nplugin also works on **claude.ai** and **Cowork**. Prefer tools over skills? The\nMCP setup above works for Desktop too — and that one *can* be scripted.\n\n<details>\n<summary><b>Skills by hand — Codex, Cursor, Antigravity, OpenClaw, Hermes</b></summary>\n\nEach host loads `SKILL.md` files from a user-scope directory: Codex\n`~/.codex/skills/` (CLI and IDE share it, v0.117.0+), Cursor `~/.cursor/skills/`,\nAntigravity `~/.gemini/skills/`, OpenClaw `~/.agents/skills/`, Hermes\n`~/.hermes/skills/` (where they become `/yt` and `/yt-agent`).\n\n```bash\n# from a checkout\ncp -R skills/yt skills/yt-agent ~/.codex/skills/\n\n# without a checkout\nfor s in yt yt-agent; do\n  mkdir -p ~/.codex/skills/$s\n  curl -LsSf \"https://raw.githubusercontent.com/dasein108/yt-mem-ai/main/skills/$s/SKILL.md\" \\\n    -o ~/.codex/skills/$s/SKILL.md\ndone\n```\n\nCodex extras: the `/yt-*` prompts (`integrations/codex/prompts/*.md` →\n`~/.codex/prompts/`) and `integrations/codex/AGENTS.md` → `~/.codex/AGENTS.md`.\nFull guide: [`skills/README.md`](skills/README.md).\n</details>\n\n### 4. The CLI on its own\n\nThe skills drive it, but it's a perfectly good standalone tool:\n\n```bash\nuvx yt-mem-ai --help          # zero-install run\nuv tool install yt-mem-ai     # or install the persistent `yt-ai` command\n```\n\nNeeds Python 3.11+ and [uv](https://docs.astral.sh/uv/); `ffmpeg` only for\n`supercut` / `frame`.\n\nThe desktop UI lives in a separate repo:\n**[yt-mem-ai-desktop](https://github.com/dasein108/yt-mem-ai-desktop)** — it\ndepends on this package and runs its own local REST API.\n\n## Getting Started\n\nInstalled and host restarted? You're ready. Just talk to your assistant — the\nskills (or MCP prompts + `analyze_video`) do the ingesting for you:\n\n> **\"Summarize https://youtu.be/dQw4w9WgXcQ\"**\n> → ingests the video (captions → whisper), then writes an executive summary\n> plus key points, in the video's own language.\n\n> **\"Give me the highlights of that video with timestamps\"**\n> → 3–8 deep-linked moments (`watch?v=…&t=123s`) anchored by semantic search.\n\n> **\"What did I watch about retrieval-augmented generation?\"**\n> → searches every transcript in your library and quotes the moments.\n\n> **\"Process my subscriptions into today's digest\"**\n> → discovers new uploads, ingests them, writes `digests/<DATE>.md`.\n\nPrefer the terminal? The same first run:\n\n```bash\nyt-ai fetch 'https://www.youtube.com/watch?v=VIDEO_ID'   # ingest one video\nyt-ai search \"what was said about embeddings\"            # search your library\nyt-ai status                                             # what's in the store\n```\n\nEverything lands in `~/.yt-mem-ai/` (library, logs, downloads).\n\n> **The first run is slow — that's expected.** Installing pulls the ML stack\n> (torch, LanceDB, sentence-transformers ≈ **1 GB** on disk), and your first\n> `fetch` or `search` downloads the embedding model on top of that. If a video\n> has no captions, the Whisper model (`small`, ≈ 460 MB) downloads too — the\n> captions path never needs it. All of it is cached, so it happens once, not per\n> video. On a GUI host the first MCP launch can outlast the app's startup check\n> for the same reason: run `uvx --from 'yt-mem-ai[mcp]' yt-ai-mcp --help` once in\n> a terminal to warm the cache, then reopen the app.\n\n**Daily routine**\n\n```bash\nyt-ai discover               # what's new in your subscriptions\nyt-ai fetch-pending          # transcribe today's batch\n```\nthen in your assistant: *\"process subscriptions\"* → per-video summaries and\n`digests/<DATE>.md`, and optionally\n`yt-ai compile --out compilations/$(date +%F).md` for the day's highlights as\nclickable links.\n\n## Usage\n\n### Talking to your assistant (skills & prompts)\n\nTwo skills ship with the plugin. MCP hosts get the same playbooks as prompts\n(`yt_summarize`, `yt_highlights`, `yt_qa`, `yt_presentation`, `yt_digest`,\n`yt_review`, `yt_group`), so nothing is lost without skill support.\n\n| Skill | Use it for |\n|---|---|\n| **`yt`** | the entry point — any operation and the full pipelines (daily routine, single video); hands analysis to `yt-agent` |\n| **`yt-agent`** | the scenarios — one video → summary / highlights / Q&A / presentation; subscriptions → daily digest; a cross-video review; a group of videos |\n\n| What you say | What happens | Where it lands |\n|---|---|---|\n| \"summarize `<url>`\" | ingest → executive summary + key points | chat, `save_summary` in the store |\n| \"highlights for `<url>`\" | 3–8 timestamped, deep-linked moments | chat + store |\n| \"Q&A about `<url>`\" | 3–6 grounded question/answer pairs | chat + store |\n| \"make a presentation from `<url>`\" | `---`-separated slide deck | `slides/<id>.md` |\n| \"process subscriptions\" | discover → ingest → per-video analysis | `digests/<DATE>.md` |\n| \"review what I watched this week\" | cross-video themes essay | `reviews/<DATE>.md` |\n| \"analyze these videos: `<ids/urls/channel>`\" | ingest a set → per-video + synthesis | `groups/<label>.md` |\n\nSkills never touch the database directly — they call the CLI, so the same\nworkflow runs on any host. Install or paste them by hand:\n[`skills/README.md`](skills/README.md).\n\n### MCP tools\n\nThe `yt-ai-mcp` server exposes the whole engine as typed tools. `analyze_video`\nis the one-step entry point: it ingests and returns the transcript so the model\ncan write the summary itself.\n\n| Category | Tool | Description |\n|---|---|---|\n| **Analyze** | `analyze_video` | Ingest a video and return its transcript (+ title, channel, language, existing summary). Call this first for any summarize / highlight / Q&A request. |\n| **Ingest** | `fetch` | Download + transcribe + embed one video (`force`, `captions_only`, `prefer_whisper`). |\n| | `discover` | New uploads from your subscription feed (incremental; `after`, `deep`, `min_duration`). |\n| | `fetch_pending` | Batch-ingest everything discovered since a date. |\n| | `channel_list` | Enumerate a channel's recent uploads (no ingest). |\n| **Library** | `search` | Hybrid / vector / FTS search over every chunk, with timestamps. |\n| | `show` | Metadata + full transcript for one video. |\n| | `list_videos` | List stored videos by status / date / channel. |\n| | `status` | Counts by lifecycle status. |\n| **Summaries** | `save_summary` | Persist a summary + highlights + Q&A so `compile` and `supercut` can use them. |\n| **Taste** | `like` / `dislike` | Record feedback for one video. |\n| | `recommend` | Rank unrated videos by similarity to what you liked. |\n| **Media** | `compile` | Deep-linked highlights doc, budget-bounded by minutes. |\n| | `supercut` | Render the highlight selection into one labeled mp4 (needs ffmpeg + network). |\n| | `frame` | Grab a still frame at a timestamp. |\n| **Config** | `config_list` / `config_get` | Inspect settings, values, and where each came from (secrets masked). |\n| | `config_set` / `config_unset` | Change settings from chat — proxy creds, cookies browser, embedding model. |\n| **Maintenance** | `reembed` | Re-embed the whole library after changing the embedding model. |\n\nServer details, prompt list, and raw config: [`integrations/mcp/README.md`](integrations/mcp/README.md).\n\n### CLI commands\n\n```bash\nyt-ai fetch <url>            # download + transcribe + embed + store one video\nyt-ai fetch <url> --captions-only  # captions only: no audio download / no whisper (fails if none)\nyt-ai transcript <url>       # same pipeline\nyt-ai discover               # new subscription uploads (--after/--deep/--min-duration/--json); incremental by default\nyt-ai fetch-pending          # batch-fetch pending 'discovered' videos (since --since, default today; --limit)\nyt-ai list                   # list stored videos (--status/--since/--json)\nyt-ai show <video_id>        # metadata + transcript (--json)\nyt-ai status                 # counts by status\nyt-ai search \"<query>\"       # semantic search (--hybrid/--fts/--vector, -k N)\nyt-ai save-summary <id> \"<summary>\" --highlights '<json>' --qa '<json>'  # persist a summary (used by skills)\nyt-ai like <video_id>        # mark liked (feeds recommendations)\nyt-ai dislike <video_id>     # mark disliked\nyt-ai recommend              # rank your unrated fetched videos by taste (--limit/--json)\nyt-ai compile                # deep-linked highlights doc, budget-bounded (--since/--max-minutes/--json/--out)\nyt-ai supercut               # video reel of highlights, re-downloaded + labeled (--since/--max-minutes/--out/--keep-clips)\nyt-ai frame <video_id> --at <ts>  # still frame at a timestamp (seconds or H:M:S) → frames/<id>_<s>s.png\nyt-ai reembed                # re-embed all chunks with the current YT_EMBEDDING_* config\nyt-ai channel-list <url>     # list a channel's recent uploads (--limit/--from/--to/--json); enumerate only\nyt-ai config list            # get/set any .env setting: config get/set/unset/path (reconfigure from CLI or chat)\n```\n\n## Examples\n\n**Case: a full PDF textbook from a 10-part YouTube course.**\n[`examples/defi-crypto-options.pdf`](examples/defi-crypto-options.pdf) — a\n96-page Russian educational book built from the series *«DeFi. Бесплатный\nвводный курс по крипто-опционам»* ([@Menaskop](https://www.youtube.com/@Menaskop)).\n\nPipeline: identify the 10 series videos → pull `ru-orig` captions (yt-dlp +\nbrowser cookies; no Whisper needed) → structured per-video digests → one shared\nspine (glossary, notation, figure catalog) → 10 rewritten chapters (~28.5k words)\n+ 47 redrawn vector figures → assembled and rendered with [Typst](https://typst.app).\nNot a summary — first-principles chapters with worked examples, diagrams,\nglossary, and per-chapter deep-links back to each video.\n\n## Configuration\n\n**Nothing is required to start** — defaults put the store, logs, and downloads\nunder `~/.yt-mem-ai/` and use a local embedding model. Tune it when you need to:\n\n| Setting | What it does |\n|---|---|\n| `YT_STORE_PATH` | LanceDB directory |\n| `YT_EMBEDDING_BACKEND` | `local` (sentence-transformers) or `openai` |\n| `YT_EMBEDDING_MODEL` | e.g. `paraphrase-multilingual-MiniLM-L12-v2` for non-English libraries |\n| `OPENAI_API_KEY` | only for the `openai` embedding backend |\n| `YT_COOKIES_BROWSER` | `chrome`/`firefox`/… — fixes YouTube's \"confirm you're not a bot\" |\n| `YT_CAPTION_LANGS` | preferred caption languages (default `en`, falls back to any track) |\n| `WEBSHARE_PROXY_*`, `YT_USE_WEBSHARE` | optional rotating proxy |\n| `YT_CHUNK_TARGET_S` | chunk length for embeddings |\n\n**Configure from the CLI or an agent** — instead of editing `.env` by hand, use\n`yt-ai config` (or the MCP `config_*` tools, so an agent can reconfigure itself\nfrom chat):\n\n```bash\nyt-ai config list                  # every setting, value, and source\nyt-ai config set WEBSHARE_PROXY_USERNAME <user>\nyt-ai config set WEBSHARE_PROXY_PASSWORD <pass>\nyt-ai config set YT_EMBEDDING_MODEL paraphrase-multilingual-MiniLM-L12-v2\nyt-ai config get OPENAI_API_KEY    # secrets masked (--reveal to show)\n```\n\n`set` writes the global config file (`~/.yt-mem-ai/config.env`) by default so the\nMCP server picks it up regardless of its working directory; `--project` writes\n`./.env`. Precedence: process env > project `.env` > global config file, and\n`config list` shows which one each value comes from.\n\n## Under the hood\n\nEverything below is optional reading — internals, tuning, and developer notes.\n\n### How it works\n\n```\nyt-dlp → captions (or Whisper) → chunks → embeddings → LanceDB\n                                                          ↓\n                     your assistant reads + writes summaries back\n```\n\nThe CLI does the heavy IO and owns the store; the skills and MCP tools are thin\ncallers. A video moves through `discovered → downloaded → transcribed →\nsummarized`; live streams get a terminal `stream` status and are skipped by batch\ningestion (transcribe one on demand with `yt-ai fetch <url>`). Storage is an\nembedded **LanceDB** (`videos`, `channels`, `transcripts`, `chunks`, `summaries`,\n`feedback`), with per-chunk vectors plus a full-text index — that's what makes\nsearch hybrid.\n\n### Command details\n\n**Rate & recommend** — like/dislike videos you've fetched, then `yt-ai\nrecommend` ranks the rest by similarity to what you liked (minus what you\ndisliked), using their transcript embeddings. Before you've liked anything it\nfalls back to most-recently-published.\n\n**`discover` is incremental** — it pulls the newest feed entries in one flat\ncall (capped by `YT_DISCOVER_FEED_LIMIT`), stamps each with an approximate\ntimestamp, and keeps only those newer than the last run's high-water mark minus\na 1h overlap (`YT_DISCOVER_OVERLAP_S`), so hour-rounded dates never miss a\nboundary video. Already-processed videos are filtered out. `--after YYYY-MM-DD`\noverrides the cutoff.\n\n**`compile` vs `supercut`** — `compile` renders the day's highlights as markdown\ndeep links (`watch?v=ID&t=<start>s`), newest-video-first and bounded by\n`--max-minutes` (default 20); it's instant and prints to stdout unless you pass\n`--out`. `supercut` re-downloads each highlight's section at 720p, burns a label\nonto it, and concatenates everything into `supercuts/<date>.mp4` plus a\n`.refs.md` sidecar listing sources (and any clips skipped after a failure) — much\nslower, needs network + `ffmpeg`, but shareable.\n\n### Embeddings, proxy, and other tuning\n\n**Embeddings:** `YT_EMBEDDING_BACKEND=local|openai`. Local uses\nsentence-transformers (`YT_EMBEDDING_MODEL`, default `all-MiniLM-L6-v2`) — for\nnon-English libraries set `paraphrase-multilingual-MiniLM-L12-v2` (384-d, 50+\nlanguages) so semantic search works cross-language. `openai` uses\n`text-embedding-3-small|large` (needs `OPENAI_API_KEY`). After changing the model,\nrun `yt-ai reembed` to migrate the existing library (re-embeds all chunks; no\nre-fetch).\n\n**Proxy / VLESS:** `YT_USE_WEBSHARE` defaults **off**. If you already run a\nsystem-level proxy/VPN (VLESS/Xray etc.), leave it off — traffic rides that\ntunnel. Stacking the Webshare proxy on top breaks the authenticated\nsubscription feed (its CONNECT tunnel returns `405`). Only set\n`YT_USE_WEBSHARE=true` if you have no other proxy and YouTube rate-limits your\nraw IP. Discover tuning: `YT_DISCOVER_FEED_LIMIT` (newest-N cap, default 60),\n`YT_DISCOVER_OVERLAP_S` (incremental overlap, default 3600), `YT_DISCOVER_TIMEOUT_S`.\n\n**Working from a checkout?** `uv sync --extra dev`, then `cp .env.example .env`\nif you'd rather keep settings project-local than in `~/.yt-mem-ai/config.env`.\n\n### Use as a Python package\n\n`yt-mem-ai` is a normal library — the CLI is a thin Typer shell over `run_*`\ncores you can call directly. Everything is local: no server, no API key (unless\nyou pick the `openai` embedding backend).\n\n```bash\npip install yt-mem-ai     # or: uv add yt-mem-ai\n```\n\n```python\nfrom dataclasses import replace\nfrom pathlib import Path\n\nfrom yt_mem_ai.config import load_config\nfrom yt_mem_ai.cli import open_store, run_fetch, run_search, run_list, run_save_summary\nfrom yt_mem_ai.store import db as store\n\n# Config comes from ~/.yt-mem-ai/config.env < ./.env < process env.\n# Override any field in code (Config is a frozen dataclass):\ncfg = replace(load_config(), store_path=Path(\"~/.yt-mem-ai/lance\").expanduser())\n\ndb = open_store(cfg)          # opens LanceDB + creates tables/indexes once\n                              # pass db=... to every run_* call to reuse it\n\n# 1. Ingest: download → transcribe (captions → whisper) → chunk → embed → store\nvideo_id = run_fetch(\"https://www.youtube.com/watch?v=dQw4w9WgXcQ\", cfg, db=db)\n# captions only (no audio download, no whisper):\n# video_id = run_fetch(url, cfg, db=db, captions_only=True)\n\n# 2. Read what was stored\nvideo = store.get_video(db, video_id)\ntext = store.get_transcript_text(db, video_id)\nprint(video.title, video.channel, video.duration_s, len(text or \"\"))\n\nfor c in store.list_chunks(db, video_id)[:3]:\n    print(f\"[{c['start_s']:.0f}s] {c['text'][:80]}\")\n\n# 3. Semantic search across the whole library (hybrid | vector | fts)\nfor hit in run_search(cfg, \"retrieval augmented generation\", mode=\"hybrid\", k=5, db=db):\n    print(hit[\"video_id\"], hit[\"start_s\"], hit[\"text\"][:100])\n\n# 4. Bring your own LLM: summarize the transcript however you like, then persist\nsummary_md = my_llm(text)                       # any model / provider\nrun_save_summary(\n    cfg, video_id, summary_md,\n    highlights_json='[{\"t\": 42, \"text\": \"key moment\"}]',\n    qa_json='[{\"q\": \"What is it about?\", \"a\": \"...\"}]',\n    db=db,\n)\nprint(store.get_summary(db, video_id))\n\n# 5. Library queries\nfor v in run_list(cfg, status=\"transcribed\", since=\"2026-01-01\", db=db):\n    print(v.video_id, v.published_at, v.title)\n```\n\nOther cores, same shape (`run_x(cfg, ..., db=db)`): `run_discover`,\n`run_fetch_pending`, `run_channel_list`, `run_recommend`, `run_feedback`,\n`run_compile`, `run_supercut`, `run_frame`, `run_reembed`. Lower-level pieces\nare importable too — `yt_mem_ai.download.download`, `yt_mem_ai.transcript.get_transcript`,\n`yt_mem_ai.store.embeddings.build_embedder` / `chunk_segments`,\n`yt_mem_ai.store.db` (LanceDB CRUD + `search_chunks`).\n\nThe store is plain LanceDB, so you can also open it directly:\n\n```python\nimport lancedb\nfrom pathlib import Path\ntbl = lancedb.connect(Path(\"~/.yt-mem-ai/lance\").expanduser()).open_table(\"chunks\")\ndf = tbl.to_pandas()      # video_id, start_s, end_s, text, vector\n```\n\n### Logging\n\nThe CLI writes structured JSON events to **`logs/common.jsonl`** (via\n`obs.log_event`/`blog`) — one object per line, `{ts, source, level, event, msg,\n...ctx}`. Override the path with `YT_LOG_FILE`; it's gitignored. Inspect with jq:\n\n```bash\njq -c 'select(.level==\"error\")' logs/common.jsonl   # every error\ntail -f logs/common.jsonl | jq -c '{ts,event,msg}'  # live tail, compact\n```\n\n### Tests\n\n```bash\nuv run pytest -q                       # offline unit tests (fake embedder)\nYT_RUN_INTEGRATION=1 uv run pytest -q  # + real sentence-transformers integration\n```\n\n### Releasing (maintainers)\n\nVersion comes from the git tag (hatch-vcs). Tag, build, and publish:\n\n```bash\ngit tag -a vX.Y.Z -m \"vX.Y.Z\" && git push origin vX.Y.Z\nuv build                                # → dist/ (sdist + wheel)\nsh scripts/publish.sh dist/yt_mem_ai-X.Y.Z*   # uploads to PyPI\n```\n\n`scripts/publish.sh` loads `UV_PUBLISH_TOKEN` from `.env` (gitignored) on demand,\nso you don't export it each time — add `UV_PUBLISH_TOKEN=pypi-…` to `.env` once\n(see `.env.example`). Equivalently: `set -a; . ./.env; set +a; uv publish dist/*`.\nRotate the token on PyPI if it's ever exposed.\n",
  "bytes": 24797,
  "sha": "acfb45211ec85f1c57cc1eb1db600c68fb2427fd0da50413f7b56bb6cc0b4cab",
  "repo_slug": "dasein108/yt-mem-ai",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_dasein108_yt_mem_ai_0bde6d94/readme"
}