335 lines
19 KiB
Markdown
335 lines
19 KiB
Markdown
---
|
||
name: youtube-knowledge-ingestion
|
||
description: "AUTO-TRIGGER: If the operator's message consists solely of a YouTube URL (youtube.com/watch, youtu.be, youtube.com/shorts — no other words), ALWAYS run the full ingestion flow immediately, without asking any clarifying questions: 1. Verbatim transcript → ai_vault_kb (the vault) per the \"Transcript Ingestion (verbatim)\" section (dedup-first, separate doc if a recipe/summary doc for the video already exists). 2. Distilled summary → Cognee brain (the brain) per the \"Brain Injection (Cognee)\" section. 3. If the video's description or pinned comment links a workflow or downloadable assets, download them to the NAS stock library per the existing procedure. 4. Reply with a minimal 4-line completion status (Brain ingest / Vault ingest / Workflow dl / Workflow(s)); write the full proof report (doc_id, chunk count, excerpt, BM25 outputs, file paths + sizes) to ~/workspace/general/logs/yt_ingestion_proofs.log instead of sending it to the operator. Use when user drops a YouTube link. Transcript→vault+brain→NAS."
|
||
version: 1.1.0
|
||
platforms: [linux]
|
||
---
|
||
|
||
# YouTube Knowledge Ingestion Pipeline
|
||
|
||
## AUTO-TRIGGER (read first — highest priority)
|
||
|
||
AUTO-TRIGGER: If the operator's message consists solely of a YouTube URL
|
||
(youtube.com/watch, youtu.be, youtube.com/shorts — no other words), ALWAYS run the full
|
||
ingestion flow immediately, without asking any clarifying questions:
|
||
1. Verbatim transcript → ai_vault_kb (the vault) per the "Transcript Ingestion (verbatim)"
|
||
section (dedup-first, separate doc if a recipe/summary doc for the video already exists).
|
||
2. Distilled summary → Cognee brain (the brain) per the "Brain Injection (Cognee)"
|
||
section.
|
||
3. If the video's description or pinned comment links a workflow or downloadable assets,
|
||
download them to the NAS stock library per the existing procedure.
|
||
4. Reply with a minimal 4-line completion status (see "Completion output" below); write
|
||
the full proof report to ~/workspace/general/logs/yt_ingestion_proofs.log instead of
|
||
sending it to the operator.
|
||
|
||
**The failure mode this trigger exists to prevent (recurring user correction):**
|
||
loading the `youtube-content` skill and producing a chat summary. A bare URL is NOT a
|
||
request for a summary — it is a request to run THIS pipeline. Do NOT load
|
||
`youtube-content` for a bare URL; load THIS skill (`youtube-knowledge-ingestion`).
|
||
Do NOT summarize the video in chat under any circumstances. The user has corrected
|
||
this multiple times ("WHY DO YOU KEEP DOING THIS — YOU HAVE A YT INGEST SKILL").
|
||
The two skills are easy to confuse: `youtube-content` = fetch transcript + format
|
||
(summary/thread/blog); `youtube-knowledge-ingestion` = the full transcript→vault +
|
||
summary→brain + workflow→NAS pipeline. A bare URL always means the latter.
|
||
|
||
## When to use
|
||
|
||
User drops a YouTube link for AI/ML video content (ComfyUI workflows, LTX, MiniMax,
|
||
Krea, model tutorials, prompting guides). Run the full four-step pipeline — never skip
|
||
any step.
|
||
|
||
## Pipeline (always all four steps)
|
||
|
||
### 1. Transcript
|
||
|
||
Load the `youtube-content` skill and fetch:
|
||
|
||
```bash
|
||
uv run python3 <SKILL_DIR>/scripts/fetch_transcript.py "URL" --text-only --timestamps
|
||
```
|
||
|
||
If `youtube-transcript-api` is missing, install with `pip3 install --user youtube-transcript-api`.
|
||
|
||
### 2. Vault Injection (ai_vault_kb) (MANDATORY)
|
||
|
||
Load the `ai-vault-kb` skill. Always dedup-first, then ingest:
|
||
|
||
```bash
|
||
# Dedup check
|
||
python3 /home/n8n/bin/ai_vault_kb.py search --query "<key topic>" --limit 5
|
||
|
||
# Ingest — use --type workflow for tutorials
|
||
python3 /home/n8n/bin/ai_vault_kb.py add \
|
||
--type workflow \
|
||
--title "Descriptive Title — Key Topics" \
|
||
--stage <t2v|i2v|upscale|...> \
|
||
--tool <ltx-video|minimax-h3|krea2|...> \
|
||
--host 10.0.0.202 \
|
||
--trust community \
|
||
--importance 0.7-0.85 \
|
||
--tags "comma,separated,keywords,creator-name" \
|
||
--url "https://www.youtube.com/watch?v=VIDEO_ID" \
|
||
--content "..." \
|
||
--json
|
||
|
||
# Verify BM25 leg
|
||
python3 /home/n8n/bin/ai_vault_kb.py search --query "<distinctive phrase>" \
|
||
--mode bm25 --doc-id <doc_id>
|
||
```
|
||
|
||
**Content format**: Dense, factual technical summary. Use CAPITALIZED section headers.
|
||
Include specific settings, model names, thresholds, commands, and failure modes.
|
||
This is a technical reference, not a blog post.
|
||
|
||
**MANDATORY: workflow links in the vault content.** Every vault entry must include a
|
||
`## WORKFLOW LINKS` section listing the DOWNLOADED workflow files on NAS (TrueNAS
|
||
10.0.0.117, proxmoxBackup/ai_vid_stock_material/workflows/, exact filenames + the
|
||
smbclient get command), the source repo URL, and the video URL. The NAS copies are
|
||
the primary links — the user wants links to the downloaded workflows, not upstream
|
||
URLs. If the description links elsewhere (Patreon etc.) and is unreachable, say so
|
||
in the content. Append as a separate chunk via `--doc-id` if the main content was
|
||
already ingested.
|
||
|
||
**Tag strategy**: model name, tool name, creator name, key techniques. Tags are
|
||
exact-match keyword indexes.
|
||
|
||
### 3. Brain Injection (Cognee) (MANDATORY)
|
||
|
||
Load the `cognee-brain` skill. Write the distilled summary to the shared Cognee
|
||
brain (10.0.0.23) as a narrative finding — LLM extraction pulls out the entities
|
||
(models, tools, creators) and facts (claims, settings, comparisons) automatically:
|
||
|
||
Call the Cognee MCP tool `mcp__cognee__remember` with:
|
||
- `data` = the distilled summary (2-4 sentences)
|
||
- `dataset_name` = `homelab-stack`
|
||
- omit `session_id` (permanent memory — runs add + cognify, builds the graph)
|
||
|
||
- `remember` is synchronous (`status: completed` means the graph is built). No
|
||
polling needed; verify later with `recall` if needed.
|
||
- Always use dataset `homelab-stack` (the single shared brain dataset). Never
|
||
create a second dataset.
|
||
- The brain holds the distilled facts; the vault (ai_vault_kb) holds the verbatim
|
||
transcript. Both are written for every video — never skip either.
|
||
|
||
**MCP timeout + REST fallback (learned 2026-08-29).** The MCP `remember` call can
|
||
fail with `TimeoutError: MCP call timed out after 120.0s` because cognify is
|
||
variable — the REST path took 77s for a 6-item ingest, while MCP full-size payloads
|
||
ran 9.8–12.2s. The MCP server itself is healthy; it is the client-side 120s
|
||
per-tool-call timeout that aborts slow cognify runs. Two-part fix:
|
||
|
||
1. **Raise the timeout** in `~/.hermes/profiles/general/config.yaml` (cognee MCP
|
||
block): `timeout: 120` → `timeout: 300`. Takes effect on next Hermes restart
|
||
(MCP connections are read once at startup). Note: the `patch` tool refuses to
|
||
edit Hermes config files — use terminal Python for an exact string replace, then
|
||
`python3 -c "import yaml; yaml.safe_load(open('config.yaml'))"` to validate.
|
||
2. **REST fallback** when MCP times out (documented in the `cognee-brain` skill):
|
||
|
||
```bash
|
||
# Write (synchronous; returns status:completed + items_processed)
|
||
curl -s -m 300 -X POST "http://10.0.0.23:8080/api/v1/remember" \
|
||
-F "data=@/tmp/brain_summary.txt" \
|
||
-F "datasetName=homelab-stack"
|
||
|
||
# Verify (field names are query + searchType, NOT query_text/query_type)
|
||
curl -s -m 60 -X POST "http://10.0.0.23:8080/api/v1/search" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"query":"<distinctive phrase>","datasets":["homelab-stack"],"searchType":"HYBRID_COMPLETION"}'
|
||
```
|
||
|
||
A `status: completed` from the REST write is proof the graph is built — no separate
|
||
cognify step. If the MCP call times out, do NOT retry it blindly; use the REST path
|
||
and verify with the search call above.
|
||
|
||
### 4. NAS Workflow Download
|
||
|
||
If the video description contains workflow links (GitHub repos, direct JSON files),
|
||
extract the description with `yt-dlp --print description "URL"`, clone the repos,
|
||
and copy workflow JSONs to the NAS:
|
||
|
||
```bash
|
||
# Clone
|
||
cd /tmp && rm -rf <repo> 2>/dev/null
|
||
git clone --depth 1 <repo-url>
|
||
|
||
# Find workflows
|
||
find /tmp/<repo> -name "*.json"
|
||
|
||
# Copy to NAS with creator prefix for disambiguation
|
||
smbclient -N //10.0.0.117/proxmoxBackup \
|
||
-c 'cd ai_vid_stock_material/workflows; put "<local>" "<creator>-<descriptive>.json"'
|
||
```
|
||
|
||
**Naming convention**: `<creator>-<model>-<workflow-type>.json`
|
||
Examples: `amao2001-ltx2.5-video_ltx2_5_t2v1.json`, `vionex-krea2-film-studio-v01.json`
|
||
|
||
**Target**: `proxmoxBackup/ai_vid_stock_material/workflows/` on TrueNAS (10.0.0.117).
|
||
|
||
**ComfyUI custom-node repos (no workflow JSONs) → `scripts/`, not `workflows/`.**
|
||
When the description links a ComfyUI custom-node pack (e.g. PlagueKind's
|
||
`ComfyUI-PlagueKind-Nodes` — the SLA attention node), the repo is Python source with
|
||
no `example_workflows/*.json` to copy. Archive it as a tarball under
|
||
`ai_vid_stock_material/scripts/` (same pattern as full apps — see
|
||
`references/fetch-path-and-walled-links.md`):
|
||
|
||
```bash
|
||
cd /tmp && rm -rf <repo> && git clone --depth 1 <repo-url>
|
||
COMMIT=$(cd <repo> && git log -1 --format=%h)
|
||
tar czf <creator>-<repo>-<commit>.tar.gz <repo>
|
||
smbclient -N //10.0.0.117/proxmoxBackup \
|
||
-c 'cd ai_vid_stock_material/scripts; put /tmp/<tarball> <tarball>'
|
||
```
|
||
|
||
`workflows/` stays reserved for ComfyUI JSONs; `scripts/` is the home for node packs
|
||
and tools. Record the commit hash in the WORKFLOW LINKS section.
|
||
|
||
## Transcript Ingestion (verbatim) — when the task says "transcript"
|
||
|
||
When the task asks for the TRANSCRIPT (not a summary/recipe), the vault doc must contain
|
||
the verbatim spoken text. A distilled recipe summary is NOT a transcript.
|
||
|
||
**Omit useless segments.** "Verbatim" means the informative spoken content word-for-word —
|
||
not the filler around it. Cut entirely: sponsor reads / ad segments, song lyrics and
|
||
music-only passages, giveaway/merch/Patreon plugs, like-and-subscribe boilerplate, and
|
||
unrelated channel promo. Replace each cut with a one-line marker at that spot — [sponsor
|
||
segment omitted], [music omitted], [channel promo omitted] — so the cut is visible and
|
||
auditable. When in doubt, keep it: anything touching the technical content (settings,
|
||
models, node names, reasoning, results) is never filler, even if it sounds chatty. The
|
||
word count in the summary header notes omissions, e.g. "2,140 words (3 segments omitted: 2
|
||
sponsor, 1 music)."
|
||
|
||
1. **Fetch the caption track**: `yt-dlp --skip-download --write-auto-subs --write-subs
|
||
--sub-langs "en.*" <url>` (fall back to `--sub-langs en` if needed). Clean the VTT/SRT
|
||
to plain text: strip WEBVTT headers, cue timestamps, and inline `<c>`/timestamp tags;
|
||
dedupe rolling-caption repeated lines. Result must read as continuous spoken sentences.
|
||
2. **Body layout**: short distilled summary header (10–15 lines max) at top, then the FULL
|
||
verbatim transcript. Title pattern: `YT: <video title> (<video-id>) — transcript`.
|
||
Use `--type research` (house pattern for video transcripts), `--trust community`,
|
||
`--url <video-url>`, tags including the video id.
|
||
3. **Helper only**: `python3 /home/n8n/bin/ai_vault_kb.py add ...` — never raw Qdrant HTTP
|
||
(bare-vector upserts miss the BM25 sparse slot and are invisible to hybrid search).
|
||
4. **Dedup first**: `search --query "<video-id>"`; ≥0.85 skip · 0.70–0.84 add only if
|
||
meaningfully new · <0.70 add. If a summary/recipe doc for the same video already exists,
|
||
add the transcript as a SEPARATE doc and mention the other doc_id in the body — do not
|
||
overwrite the recipe doc.
|
||
5. **Chunk boundaries + ordering**: the helper chunks at 1200 chars with 150 overlap, and
|
||
overlap starts land mid-word. To guarantee no chunk starts/ends mid-word, pre-split the
|
||
body at sentence boundaries into ≤1200-char pieces and add them sequentially with
|
||
`--doc-id` (each piece ≤1200 chars becomes exactly one chunk). Pass `--chunk-index N`
|
||
(0-based) on every add-call so reading order is recoverable from metadata: the summary
|
||
header piece is `--chunk-index 0`, the next piece `--chunk-index 1`, and so on through
|
||
the transcript body; the WORKFLOW LINKS piece is the last (highest) index. Prefer the
|
||
bundled `scripts/ingest_transcript.py` — it does the pre-split, the sequential indexed
|
||
adds, and the self-QA gate in one run. See `references/transcript-ingestion-detail.md`
|
||
for the chunking algorithm, the `--chunk-index` backfill context, and the proof-log
|
||
entry format.
|
||
6. **Self-QA gate before reporting done (mandatory)**:
|
||
- get the doc back; confirm the body contains verbatim spoken sentences (first-person
|
||
narration, not bullets);
|
||
- confirm no chunk begins or ends mid-word (print first/last 10 chars of every chunk);
|
||
- run a search on one distinctive literal phrase copied from the body and confirm the
|
||
doc surfaces (proves the BM25 slot).
|
||
- **chunk-index ordering**: run `list --doc-id <id> --json` and confirm the
|
||
`chunk_index` values are exactly 0 through N−1, each appearing once. Then read the
|
||
pieces back in index order and confirm they reproduce the narrative sequence
|
||
(summary header → transcript body → WORKFLOW LINKS). A doc with duplicate or missing
|
||
indices fails the gate — fix it by rebuilding the doc: delete --doc-id <id> --yes,
|
||
then re-add ALL pieces in order with correct --chunk-index values (add --doc-id
|
||
appends — re-adding a single piece would duplicate it), then re-run this gate.
|
||
7. **Completion report → log file, not chat.** Do NOT send the proof report to the
|
||
operator. Instead append it to `~/workspace/general/logs/yt_ingestion_proofs.log`
|
||
(create the dir if needed) under a dated header per run. The log entry contains the
|
||
same content as before: doc_id, chunk count, a 2–3 line verbatim excerpt, the BM25
|
||
search outputs, the chunk-index ordering check output (the `list --doc-id <id> --json`
|
||
result showing chunk_index 0..N−1 each once), and every downloaded file's full NAS
|
||
path + size. Then reply to the operator with only the minimal 4-line status per the
|
||
"Completion output" section below.
|
||
|
||
## Completion output (minimal — replaces the chat proof report)
|
||
|
||
After a run, reply to the operator with EXACTLY these four lines and nothing more:
|
||
|
||
```
|
||
Brain ingest: done
|
||
Vault ingest: done
|
||
Workflow dl: done
|
||
Workflow(s): <filename(s) as saved on the NAS>
|
||
```
|
||
|
||
Rules:
|
||
|
||
1. **"done" is earned, not assumed.** A line may say "done" only after its self-QA gate
|
||
actually passed — the internal checks (verbatim verify, chunk edges, BM25 probe, NAS
|
||
size verify) still run in full; only the reporting shrinks. If a step failed or was
|
||
skipped, say so on that line in a few plain words instead of "done":
|
||
- Brain ingest: failed — <one-line reason>
|
||
- Vault ingest: failed — <one-line reason>
|
||
- Workflow dl: none linked
|
||
- Workflow(s): <none, or the filenames if some succeeded>
|
||
2. **Full proof report goes to the log file**, not chat:
|
||
`~/workspace/general/logs/yt_ingestion_proofs.log` (create the dir if needed). Append
|
||
one entry per run with a dated header (e.g. `## 2026-08-17 BjZvVx6sDmE — TaoofAI EP.1`)
|
||
containing: doc_id, chunk count, verbatim excerpt, BM25 search outputs, and every
|
||
downloaded file's full NAS path + size. This log path is the single place any
|
||
validator looks for proof.
|
||
3. **Keep the doc_id available.** Include it in the log entry. If the operator or a
|
||
validator asks "doc id?" after a run, answer with just the doc_id — nothing else.
|
||
|
||
## Hard rules for vault docs created from videos
|
||
|
||
- **Every doc created from a video MUST carry the video-ID tag** (e.g. `ZUzeM9OEJ4Y`)
|
||
in `--tags`, on every chunk-add call. The video ID also goes in `--url` (source_url).
|
||
- **Additionally ensure the video ID appears in each doc's TITLE** (append `(VIDEOID)` if
|
||
absent) — tags don't feed BM25, so the tag alone doesn't make the doc rank; title
|
||
placement does. The transcript title pattern already complies; older recipe/workflow
|
||
docs won't.
|
||
- **Trust enum**: `official` | `github` | `community` | `social` — video-derived docs use
|
||
`--trust community` unless the creator is the model vendor.
|
||
- **Keyword-search caveat**: the helper builds the BM25 sparse vector from title+text
|
||
ONLY — tags are payload-only and do not feed keyword search. A doc whose title and
|
||
body lack the video ID will rank low in `search --query "<video-id>"` even with the
|
||
tag present. For transcript docs the title pattern `YT: <title> (<video-id>) —
|
||
transcript` already embeds the ID; for recipe/summary docs, include the video ID in
|
||
the body (e.g. the WORKFLOW LINKS section) so at least one chunk matches.
|
||
|
||
## Hard rules for brain writes created from videos
|
||
|
||
- **Every video writes to the brain via `mcp__cognee__remember`** (narrative finding)
|
||
with `dataset_name="homelab-stack"`. The video URL goes in the data text so the
|
||
brain fact is traceable back to the video.
|
||
- **The brain write is the distilled summary, not the verbatim transcript.** Keep it to
|
||
2-4 sentences of the durable takeaways (what the video demonstrates, key settings,
|
||
verdict). The verbatim text lives only in the vault.
|
||
- **`remember` is synchronous** — `status: completed` means the graph is built. If a
|
||
validator needs proof, `mcp__cognee__recall` a distinctive phrase.
|
||
- **`status: completed` is NOT proof the content is retrievable.** A write can return
|
||
`completed` yet a later recall answers "does not contain information about <terms>".
|
||
The recall is the real gate: after every brain write, `recall` a distinctive phrase
|
||
from the summary and confirm the answer actually contains it. If it does not,
|
||
re-write the summary and re-verify — do NOT report "Brain ingest: done" on
|
||
`status: completed` alone. See `references/brain-write-verification.md`.
|
||
|
||
## Pitfalls
|
||
|
||
- **Never load `youtube-content` for a bare URL.** The bare-URL trigger means run the
|
||
full pipeline via THIS skill. Loading `youtube-content` and summarizing in chat is the
|
||
single most common failure — the user has corrected it repeatedly. If you catch
|
||
yourself about to produce a chat summary of a video, stop and run the pipeline.
|
||
- **MCP `recall` uses `search_type` (snake_case), REST uses `searchType` (camelCase).**
|
||
The `mcp__cognee__recall` tool rejects `searchType` with a pydantic validation error
|
||
("Unexpected keyword argument searchType") — pass `search_type="HYBRID_COMPLETION"`.
|
||
The REST `/api/v1/search` endpoint (curl) uses `searchType` in the JSON body. Don't
|
||
mix them up.
|
||
- **Never skip the vault injection step.** The user's memory directive explicitly
|
||
requires both transcript AND vault injection for every YouTube link.
|
||
- **Never skip the brain injection step.** Every video also writes a distilled finding
|
||
to the Cognee brain (`mcp__cognee__remember`, dataset `homelab-stack`). Vault =
|
||
verbatim transcript; brain = distilled facts. Both are mandatory.
|
||
- **Never skip the BM25 verification.** A write that can't be found via BM25 is
|
||
effectively invisible — the `ai_vault_kb.py` helper is the only interface that
|
||
produces searchable points.
|
||
- **Don't overwrite existing NAS workflows.** Use creator prefixes to avoid collisions
|
||
with workflows already in the directory.
|
||
- **The `youtube-content`, `ai-vault-kb`, and `cognee-brain` skills are protected** —
|
||
load them for reference but don't attempt to patch them. This skill is the integration
|
||
layer between them.
|