About anibon-timestamper
anibon-timestamper is a skill for producing YouTube-format topic timestamps from Anibon Official live-stream transcripts with cloud LLMs. It routes chunks to specialized subagents in parallel and can incorporate chat, stream activity, and topic references.
Key features
- 01Parallel chunk analysis by subagents
- 02Transcript preparation and chunking
- 03Topic signal and boundary detection
- 04Optional LiveChat and activity context
- 05Mood guidance from chat pulses
Use cases
- 01Label topics in Anibon Official streams
- 02Process long transcripts in chunk groups
- 03Use chat context to characterize stream moments
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ zenithth/ anibon-stream-synthesis --skill anibon-timestamperAfter installing, type/anibon-timestamperin Claude Code to confirm it loaded.
Bundled files
References and scripts installed along with SKILL.md.
.gitignoredocs/superpowers/specs/2026-08-06-per-chunk-mood-segments-design.mdreferences/anibon_emoji_dictionary.mdBUILD_WHISPERCPP_GUILD.mdINDEX.mdsubagent-prompt-template.mdsummarizer-subagent-guide.mdwhisper_pc_spec_benchmark.mdreferences/stories/.gitkeepresources/garbled_replacements.jsonscripts/align_live_chat.pyanibon-analyzer.pybuild_subagent_prompts.pydetect_boundaries.pydetect_signals.pydump_chunk_text.pymerge_timestamps.pyprepare_video.pyvalidate_mood.pyvalidate_part_coherence.pytests/__init__.pytest_align_live_chat.pytest_analyze_555_emoji.pytest_detect_signals.pytest_pack_timestamps.pytest_validate_tags.pyDetails
From the project READMEAnibon Timestamper (Frontier / Cloud Orchestrator)
A routing orchestrator skill for analyzing live stream transcripts using cloud/frontier LLMs to generate timestamps in YouTube format. Dynamically detects stream type and delegates to specialized subagents in parallel.
When to Use
- Streams or videos by "Boat" from Anibon Official that need timed topic labels using Frontier / Cloud models with parallel subagents (
anibon-chunk-timestamper,anibon-summarizer,anibon-garbled-notes). - If running locally on a single GPU (NVIDIA Tesla P100, LM Studio, Ollama, local VLM) without cloud API costs, use
anibon-timestamper-localinstead.
Sub-Skills & Permissions
REQUIRED (first): Load preparing-tools to verify dependencies (yt-dlp, ffmpeg, python3).
REQUIRED (subagent execution): Load batching-subagents-concurrency when running multi-subagent analysis (max 10 per batch turn with Model: "flash"). Ask user permission before downloading large external media or performing long web fetches.
Loaded by signal (add to prompt when needed):
anibon-world-identity— verify game/char names and Japanese convention/event terms against references before stampsanibon-stream-activity— high-res storyboard sampling for on-screen gameplay, webcam presence/AFK, and visual groundinganibon-local-transcription— whisper.cpp fallback if YouTube has no captionswhisper-corruption-recovery— recover transcript if repetition loops / corruption detected in Whisper outputanibon-livechat-analysis— parse LiveChat replay (or visual on-screen chat fallback viaextract_visual_livechat.py) so subagents can read the live from both sides (talker + chat)antigravity-vision-proxy— storyboard (sb0) frame inspection for ambiguous pronouns, game title verification, or unresolved garbled notes
Pipeline (Linear, Top-to-Bottom)
All paths relative to the skill root directory (skills/anibon-timestamper/).
0. Environment
scripts/ directory contains all helper scripts. Run <script>.py --help for flags.
Store working files in youtube_<video_id>_workspace/.
1. Initialize
Ask output language. Verify channel and speaker nicknames against resources/channels.json:
- Own Channel:
Anibon Official(@anibonofficial) - Primary Speaker:
Boat/Pu Boat(ปู่โบ๊ต/PhuBoat/โบ๊ต)
Ensure transcript speaker attribution maps to own_channel nicknames before continuing.
2. Prepare Video
python3 -X utf8 scripts/prepare_video.py "URL" --format xml --block 300 --overlap 30
# Talk-heavy → --block 600 --overlap 60
Downloads transcript, creates <workspace>/chunks/chunk_*.xml.
Important
Check Corruption: If transcript is from local Whisper transcription (or audio ≥2h), verify tail entries for repetition loops. If corruption found (>0.5 match ratio), load
whisper-corruption-recoveryskill to split, re-run corrupted tail segment, and dedup-merge before chunking.
3. Clean Transcript (Optional)
Normalizes Thai-Whisper garbled English before signal detection. The script lives in the cleaning-auto-transcripts skill — resolve from the timestamper skill root.
python3 -X utf8 ../cleaning-auto-transcripts/scripts/clean_garbled_english.py --chunks ~/youtube_<id>_workspace/chunks/
3.5 Download & Align LiveChat (Optional but preferred)
Gives each subagent the watchers' chat for its own chunk, so situation + emotion are read from BOTH talks and chat. Requires network; if a VOD has no live_chat subtitle, skip this step and rely on transcript-only emotion.
# 1. Download LiveChat replay (network required)
yt-dlp --sub-langs live_chat --write-sub --skip-download "https://www.youtube.com/watch?v=<VIDEO_ID>" -o "<workspace>/%(id)s.%(ext)s"
# 2. Parse to coarse chunks + a seconds-prefixed raw event feed
python3 -X utf8 ../anibon-livechat-analysis/scripts/parse_live_chat.py <workspace>/<id>.live_chat.json --chunk-minutes 90 --raw-events <workspace>/livechat_events.txt -o <workspace>/livechat_90/
# 3. Align raw feed to transcript chunk windows
python3 -X utf8 scripts/align_live_chat.py --events <workspace>/livechat_events.txt --chunks <workspace>/chunks/ -o <workspace>/livechat/
Output: livechat/livechat_chunk_NN.txt (per transcript chunk) + livechat/livechat_index.json. If yt-dlp reports no live_chat subtitles, continue — the subagent falls back to transcript-only.
Fallback for Edited Livestreams / Missing .live_chat.json (Visual Chat Extraction)
When a livestream has been trimmed or edited in YouTube Studio, YouTube permanently deletes the .live_chat.json chat replay track, and yt-dlp will report no chat subtitles available.
Instead of losing watcher context on high-interest moments, run extract_visual_livechat.py from anibon-livechat-analysis to OCR the burned-in chat overlay for specific peak chunks (e.g. meme bursts, high SuperChat donations, viewer Q&As, or climax reactions):
# 1. Spot-extract visual livechat for target chunk time range
python3 -X utf8 ../anibon-livechat-analysis/scripts/extract_visual_livechat.py \
--video-id <VIDEO_ID> \
--range HH:MM:SS-HH:MM:SS \
-o <workspace>/visual_livechat_events.txt
# 2. Align visual raw event feed directly to chunk windows
python3 -X utf8 scripts/align_live_chat.py \
--events <workspace>/visual_livechat_events.txt \
--chunks <workspace>/chunks/ \
-o <workspace>/livechat/
This populates <workspace>/livechat/livechat_chunk_NN.txt for the targeted chunk windows, feeding directly into analyze_555.py (Step 3.7) and subagent prompt generation without requiring a full-length video download.
3.6 Extract Activity & Webcam Timeline (Optional but preferred)
Captures on-screen gameplay/web browsing and Pu Boat's webcam presence/AFK state to eliminate Speech vs. Action divergence errors.
# 1. Download high-res storyboard (sb3 -> sb2 -> sb1 -> sb0)
yt-dlp -f "sb3/sb2/sb1/sb0" "https://www.youtube.com/watch?v=<VIDEO_ID>" -o "<workspace>/frames/storyboard.%(ext)s"
# 2. Unpack slides
python3 -X utf8 ../anibon-stream-activity/scripts/unpack_storyboard.py --mhtml "<workspace>/frames/storyboard*" --out-dir "<workspace>/frames/slides"
# 3. Extract continuous activity timeline
python3 -X utf8 ../anibon-stream-activity/scripts/extract_activity_timeline.py --slides-dir "<workspace>/frames/slides" -o "<workspace>/activity_timeline.json"
# 4. Align activity to chunk windows
python3 -X utf8 ../anibon-stream-activity/scripts/align_activity_timeline.py --timeline "<workspace>/activity_timeline.json" --chunks "<workspace>/chunks/" -o "<workspace>/activity/"
Output: <workspace>/activity/activity_chunk_NN.txt containing on-screen game/app state, webcam presence, and physical expressions for subagent injection.
3.7 Detect Thai-Laugh / Meme Pulses (Optional but preferred)
Downstream of align_live_chat.py. Thai watchers mark laughter with 555... / xD / ฮา / ขำ. A clustered burst in a short window = a meme/laugh peak. This is the only reliable laugh proxy when the autotranscript can't hear the streamer actually laughing. Emits per-chunk mood verdicts + Thai tone guidance that subagent prompts MUST weight when writing mood-bearing descriptions.
python3 -X utf8 scripts/analyze_555.py \
--livechat ~/youtube_<id>_workspace/livechat/ \
--index ~/youtube_<id>_workspace/livechat/livechat_index.json \
--out ~/youtube_<id>_workspace/mood_555.json
Output: mood_555.json — dict chunk → {density, n_markers, n_messages, peak_windows, pulse, mood, verdict, tone}. The tone field carries Thai guidance (tone + suggested verbs) matched to the chunk's mood family. Verdicts:
*_PULSE— burst passed the weighted score → mood-driven guidance.MEME_PULSE(funny),CUTE_CUNNY_PULSE(cute),SHOCK_HYPE_PULSE(hype),DRAMA_NEWS_PULSE(news/drama),ANGRY_OUTRAGE_PULSE(rant), etc.HOT/WARM— some markers, no burst → light banter / lively guidanceQUIET— low chat, no burst → neutral, free verb choice
Note
Mood is guidance, not a rule. The
tone/verbshint tells the subagent which vibe the chat carried; the AI still picks its own first verb from the situation. Only when a PULSE chunk gets timestamped as if the moment were flat doesvalidate_mood.py(Step 11.5) remind the human.Emoji Dictionary Reference: Refer to
references/anibon_emoji_dictionary.mdfor complete channel-exclusive emote mapping (:_CunnyBoat:,:_MonkeyBoat:,:_Nerd:,:_shutup:,:Grind:,:_Ripfish:,:_noname:,:_What:,:_WOW:,:_Ahh:,:_Meh:,:_MoneyBoat:,:_Tahaan:,:_KonDee:,:_NeoSlim:,:_Slim:,:_BoatSOM:) and YouTube global emotes to mood pulse weights and safety masking triggers.
If a chunk is flagged MEME_PULSE but the subagent writes a flat, factual first-verb for it, that's the tone mismatch validate_mood.py (Step 11.5) surfaces for review.
4. Analyze (Pre-flight)
Quick summary of chunk categories, gaps, byte sizes. Note: On Windows, use -X utf8 to avoid console UnicodeEncodeError.
python3 -X utf8 scripts/anibon-analyzer.py ~/youtube_<id>_workspace/
5. Detect Signals → Match Knowledge Files
TF-IDF across all chunks. Matches keywords to knowledge files per chunk.
python3 -X utf8 scripts/detect_signals.py \
--chunks ~/youtube_<id>_workspace/chunks/ \
--knowledge ./resources/knowledge.json \
--output ~/youtube_<id>_workspace/signals.json
Output: signals.json — per-chunk weighted signal: matched_files (with df/weight), weighted_matched_files (ranked), best_file, primary_topic, confidence.
Path convention: every
best_file/matched_filespath inknowledge.jsonis relative to the timestamper skill root.references/stream/*.md= local to timestamper;../anibon-world-identity/references/*.md= world-identity skill;../reference/*= top-level data dir. Resolve all of them from the timestamper root, never from the current cwd.
Rarity = main idea:
detect_signals.pyweights each matched keyword by inverse document frequency (log(N/df)). High-frequency (df high) words are daily-use filler and score 0 — ignored. Low-frequency (rare) words are the distinctive main idea. Handbest_fileto a subagent only whenconfidenceis clear; otherwise omit the knowledge file.
5.5 Load World-Identity (if signals match a game reference)
Trigger: signals.json best_file/weighted_matched_files resolves to a file under ../anibon-world-identity/references/ (i.e. post-cutoff game/char names). These names are the ones subagents hallucinate.
Action: Load the anibon-world-identity skill. It runs references/INDEX.md → cached story refs → reference SRT → websearch fallback to build a verified Thai-phoneme → EN name map. Bootstrap its game DBs first:
python3 ../anibon-world-identity/scripts/fetch_fgo_db.py --check --db "../reference/FGO and DATA/atlas_fgo.db" || \
python3 ../anibon-world-identity/scripts/fetch_fgo_db.py --db "../reference/FGO and DATA/atlas_fgo.db"
python3 ../anibon-world-identity/scripts/fetch_ygo_db.py --check --db "../reference/Yu-Gi-Oh DATA/ygo_cards.db" || \
python3 ../anibon-world-identity/scripts/fetch_ygo_db.py --db "../reference/Yu-Gi-Oh DATA/ygo_cards.db"
Inject the resolved name map into the Step 7 subagent prompts (any chunk whose signal matches one of these files) so [Story] stamps use canonical names, not phonetic guesses. Skip when stream covers well-known pre-cutoff content.
6. Detect Topic Boundaries (Optional)
For long streams with clear topic shifts. Run:
python3 -X utf8 scripts/detect_boundaries.py --chunks ~/youtube_<id>_workspace/chunks/ --signals ~/youtube_<id>_workspace/signals.json --output ~/youtube_<id>_workspace/boundaries.json
If boundaries look noisy, fall back to manual identification from signals.json: look for chunks where matched_files changes (e.g., gaming→Genshin→FGO). Note timestamps for --break-at in Step 9.
7. Spawn Subagents (Parallel)
Divide chunks into groups of 4–5 (~20–25 min each). One anibon-chunk-timestamper per group.
Run build_subagent_prompts.py to prepare input files:
python3 -X utf8 scripts/build_subagent_prompts.py <workspace>
This produces:
<workspace>/prompts_by_chunk/chunk_NN.txt: per-chunk prompt files (~15–25KB each, guaranteed underview_file's 46KB view limit to prevent mid-chunk truncation).<workspace>/prompts/group_NN.txt: group manifests listing chunk file URIs and metadata.
Important
Strict Concurrency Batching (4–6 Subagents Recommended): To prevent API 429
RESOURCE_EXHAUSTEDrate limits (especially rolling TPM exhaustion when group manifests reach ~50–100KB), launch subagents in controlled batches of 4–6 subagents per turn (max 8). Wait for each batch to finish, and ONLY THEN launch the next batch.Use Flash Model Tier: Always specify
Model: "flash"when callinginvoke_subagentfor chunk timestampers to maximize speed and rate-limit headroom.Per-Chunk Sequential Reading: Point subagents to sequentially read their assigned
file://<workspace>/prompts_by_chunk/chunk_NN.txtfiles viaview_fileto ensure 100% full-text reading without truncation.
Invoke pattern (one per group):
invoke_subagent(
"anibon-chunk-timestamper",
Model="flash",
prompt=f"""You are processing Group {g} (chunks {start} to {end}).
PREVIOUS GROUP LAST TOPIC: {prev_topic}
Read each chunk sequentially via view_file:
- file://{workspace}/prompts_by_chunk/chunk_00.txt
- file://{workspace}/prompts_by_chunk/chunk_01.txt
..."""
)
Each chunk prompt contains:
- Chunk XML/dialogue lines
- Detection signals from
signals.json(best_file+primary_topic+confidence+ rankedweighted_matched_files) - Per-chunk LiveChat log (
livechat/livechat_chunk_NN.txt) - Per-chunk on-screen visual activity log (
activity/activity_chunk_NN.txt) - Per-chunk mood verdict + tone guidance from
mood_555.json
CRITICAL: The agent reads chunks sequentially within its group and skips continuation chunks. Do NOT inject your own topic summaries — inject signals data only.
Each anibon-chunk-timestamper returns plain-text timestamp lines (typically 2–4 per group).
Important
Visual AI & Generative Tool Grounding: When the streamer tests or reacts to visual AI generators (e.g. text-to-image, video generation, or creative editing tools), distinguish between:
- The actual prompt requested by the streamer.
- What the AI model actually rendered on screen (or if it failed/refused).
- The streamer's comedic, political, or hyperbolic satirical roasts. NEVER take satirical roasts (e.g., "กลายเป็นคอมมิวนิสต์", "เหมือนสลิ่ม", "หลอนเป็นเปรต") as literal descriptions of the generated image. Always use
[Reaction]and attribute the roast clearly (e.g.ปู่โบ๊ตเหวอ TH-AI ไม่รู้จัก Jane Doe เจนเป็นสาวไซเบอร์ยืนคู่ ครม. แซวยังกะรัฐบาลจีน).
Important
Timestamp Lead-in & Off-hand Analogy Guard:
- Lead-in Anchor: Always anchor timestamp start to the opening sentence of a discussion topic. Never stamp mid-sentence after key proper nouns have already been uttered (prevents viewers from clicking and missing context).
- Off-hand Analogy Rule: Never elevate passing 1–2 sentence analogies or sarcastic roasts (e.g. comparing a show's budget to Frieren) into the primary timestamp title. Always describe the core topic (e.g. One Punch Man S3 & J.C.Staff drama) and relegate passing comparisons to parentheticals.
8. Merge Timestamps
Write each subagent's output to its own file (e.g., chunk_001.txt, chunk_002.txt). Then merge + sort chronologically:
python3 scripts/merge_timestamps.py ~/youtube_<id>_workspace/chunk_*.txt \
-o ~/youtube_<id>_workspace/all_timestamps.txt
8.5. Audit Gaps (MANDATORY before summarizer)
Enforces the NO GAPS iron rule. Run on the merged list; if it exits non-zero, spawn a fill agent for each flagged chunk (the tool prints the covering chunk_NN to re-run) and re-merge before Step 9.
python3 scripts/audit_gaps.py ~/youtube_<id>_workspace/all_timestamps.txt
# exit 0: no gaps. exit 1: prints e.g. "12m 01:13 -> 01:25 (fill around chunk_26)"
8.6 Dispatch Audio Slices to Whisper.cpp & Clean Garbled Notes (Ground Truth)
Subagents strictly emit spotter tokens (- "token" @ HH:MM:SS (chunk_NN)). Execute in two distinct phases:
Step 8.6a: Run whisper.cpp First (Orchestrator Audio Ground Truth)
- Extract all spotter notes from chunk timestamp outputs into
<workspace>/garbled_notes_raw/candidates.txt. - Run
whisper_dispatcher.pyto cluster timestamps, slice audio on-the-fly, and transcribe acoustic ground truth via localwhisper.cpp:
# Slicing & Audio Resolution:
# Option A (Recommended): Direct on-the-fly slicing from stream URL (no multi-GB download required)
python3 scripts/whisper_dispatcher.py ~/youtube_<id>_workspace --video-url "https://www.youtube.com/watch?v=<VIDEO_ID>" --verbose
# Option B (Local audio stream copy at 150x-300x speed without full video download):
URL=$(yt-dlp --extractor-args "youtube:player_client=android" -g -f 18 "https://www.youtube.com/watch?v=<VIDEO_ID>")
ffmpeg -y -i "$URL" -vn -c:a copy ~/youtube_<id>_workspace/audio.m4a
python3 scripts/whisper_dispatcher.py ~/youtube_<id>_workspace --verbose
This produces <workspace>/garbled_notes.json containing:
google_sentence: Exact surrounding sentence window fromraw_transcript.th-orig.json3.whisper_segment: Time-aligned acoustic sentence segment fromwhisper.cpp(-oj).correct: Canonical target (auto-resolved from dictionary or set by subagent).
Tip
Failed Slice Recovery (Single Cluster): If any cluster fails to slice (e.g. exit status 187 due to transient stream socket timeout):
URL=$(yt-dlp --extractor-args "youtube:player_client=android" -g -f 18 "https://www.youtube.com/watch?v=<VIDEO_ID>") ffmpeg -y -ss <start_sec> -t <duration_sec> -i "$URL" -ar 16000 -ac 1 -c:a pcm_s16le <workspace>/audio_slices/cluster_XXX_<start_sec>.wav /Users/zenithth/whisper.cpp/build/bin/whisper-cli -m /Users/zenithth/whisper.cpp/models/ggml-large-v3-turbo.bin -f <workspace>/audio_slices/cluster_XXX_<start_sec>.wav -l th --output-txtUpdate
garbled_notes.jsonwith the transcript text before passing toanibon-garbled-notes.
Step 8.6b: Call anibon-garbled-notes Subagent Later (Ground Truth Alignment & Dictionary Sync)
Invoke anibon-garbled-notes subagent with the acoustic transcripts from whisper_dispatcher.py:
invoke_subagent(
"anibon-garbled-notes",
Model="flash",
Prompt=f"""Analyze the whisper.cpp transcripts in {workspace}/garbled_notes.json.
Perform sentence-level word-by-word sequence alignment between google_sentence and whisper_segment to resolve phonetic noise slots.
Resolve canonical words, validate anti-cascade rules against raw_transcript.th-orig.json3,
update {workspace}/garbled_notes.json with confirmed targets, and run update_garbled_dictionary.py."""
)
The subagent updates <workspace>/garbled_notes.json and executes:
python3 ../cleaning-auto-transcripts/scripts/update_garbled_dictionary.py \
--from-notes ~/youtube_<id>_workspace/garbled_notes.json \
--workspace ~/youtube_<id>_workspace
# If /Users/zenithth/abss-dev exists, sync git working copy as well:
if [ -d "/Users/zenithth/abss-dev" ]; then
python3 /Users/zenithth/abss-dev/skills/cleaning-auto-transcripts/scripts/update_garbled_dictionary.py \
--from-notes ~/youtube_<id>_workspace/garbled_notes.json
fi
Warning
Avoid
--cookies-from-browseron macOS: Extracting browser cookies triggers a GUI Keychain password authentication prompt which hangs headless/CLI background agent tasks. Use--extractor-args "youtube:player_client=android"to cleanly bypass YouTube SABR HTTP 403 errors without credentials.
Caution
Anti-Cascade Ground Truth Check: Always cross-check candidate garbled notes against
raw_transcript.th-orig.json3. If a candidate contains a multi-word game/anime title (e.g.Yuri on Ice,Chaos Zero Nightmare,Where Winds Meet,SLAPP) embedded inside Thai text, it is an artifact of an aggressive cleaner rule. Never save cleaner artifacts intogarbled_replacements.json.
Outputs:
~/youtube_<id>_workspace/garbled_notes.json— all candidates (garbled,google_sentence,whisper_segment,correct,chunk,ts,cluster_span)resources/garbled_replacements.json— auto-synced across root and skill resources with canonical grouped mappings (TargetWord: [patterns...])
The dictionary is shared (resource_path() walks up to plugin root), so every future stream auto-loads the new rules. Truly unresolved proper nouns are left correct: null for human confirmation.
9. Final Assembly — anibon-summarizer (Replaces wrap + pack)
Pass the full sorted all_timestamps.txt to the anibon-summarizer subagent. It deduplicates cross-chunk overlaps, groups by macro-thematic coherence (without 3,500-byte cap over-splitting), curates essential timestamps (~40–60 stamps for long streams), writes caveman part headings, and produces the final markdown.
with open("all_timestamps.txt") as f:
merged = f.read()
invoke_subagent(
"anibon-summarizer",
prompt=f"TIMESTAMPS:\n{merged}"
)
The subagent outputs the complete output.md directly. Save it to ~/youtube_<id>_workspace/output.md.
Note
pack_timestamps.pyis still available for offline/scripted runs or when single-comment byte splitting is explicitly requested. In standard sessions, prioritize macro-thematic grouping and essential curated timestamps to preserve topical cohesion. If single-comment byte limits are explicitly requested:python3 scripts/pack_timestamps.py ~/youtube_<id>_workspace/all_timestamps.txt \ --byte-limit 2900 \ --title "<Stream Title>" \ --output ~/youtube_<id>_workspace/output.md python3 scripts/check_sections.py ~/youtube_<id>_workspace/output.md
10. Validate Sections
python3 scripts/check_sections.py ~/youtube_<id>_workspace/output.md
Checks: byte cap per section ✅, no ASR garbled patterns.
11. Validate Topic Coherence (Optional)
Cross-references timestamp game names against signals.json ground truth. Flags fabricated names or topic bleed between parts.
python3 scripts/validate_part_coherence.py ~/youtube_<id>_workspace/output.md \
--signals ~/youtube_<id>_workspace/signals.json \
--chunks ~/youtube_<id>_workspace/chunks/
11.5 Validate Mood vs Chat Pulse (Optional)
Companion to analyze_555.py. Labels each timestamp with its chunk's mood + Thai tone guidance (the verbs the AI may draw from). Guidance-only — it never rejects a verb; the AI's verb creativity stays free. Report-only; exit 0. Use it to review whether a PULSE-span stamp actually carried the chunk's energy.
python3 scripts/validate_mood.py \
--timestamps ~/youtube_<id>_workspace/all_timestamps.txt \
--mood ~/youtube_<id>_workspace/mood_555.json \
--livechat ~/youtube_<id>_workspace/livechat/ \
--index ~/youtube_<id>_workspace/livechat/livechat_index.json
12. Catalog, Archive & Dictionary Synchronization (End-of-Series Protocol)
Once output.md is generated and verified (or after a multi-part series run finishes):
-
Synchronize Garbled Notes:
- Collect and harvest all spotted
GARBLED_NOTES:from chunk timestamper subagents across all parts. - Ingest into
resources/garbled_replacements.jsonunder the"mappings"key (data["mappings"], preserving header metadata keysversion,description,note). - Synchronize across both plugin root and vendored copies (
resources/garbled_replacements.jsonandskills/anibon-timestamper/resources/garbled_replacements.json). - Commit and push updated dictionary to GitHub (
anibon-stream-synthesis.git).
- Collect and harvest all spotted
-
Ingest into
timestamp_workspace:- REQUIRED SUB-SKILL: Use
backing-up-timestamps. - Run
python3 -X utf8 import_workspace.py ~/youtube_<id>_workspace(or batch across~/youtube_*_workspace). - Automatically archives structured transcripts (
transcripts/transcript_<id>.jsonl.gz), copiesextras/<id>/, automatically rebuilds the search index (python3 -m anibon_search build), and links entries inby_video_id/timestamp_<id>.mdandREADME.md. - Commit and push
timestamp_workspaceto GitHub (ZenitHTH/timestamp-workspace.git).
- REQUIRED SUB-SKILL: Use
-
Archive Raw Workspaces:
- Move verified directories into
~/youtube_workspaces/backed_up/. - Update
workspace_pathinmetadata/catalog.json.
- Move verified directories into
Output Format
Single .md file with ═══ section blocks:
# Title | ANIBON
═════════════════════════════════════════════════════
Part 1: Section Header (⏱ เริ่ม: HH:MM:SS)
═════════════════════════════════════════════════════
HH:MM:SS - [Tag] Description
...
═════════════════════════════════════════════════════
Part 2: Section Header (⏱ เริ่ม: HH:MM:SS)
═════════════════════════════════════════════════════
...
Helper Scripts
| Script | Purpose |
|---|---|
scripts/prepare_video.py | Download + clean + chunk |
scripts/dump_chunk_text.py | Dump clean formatted text from XML chunks for subagents |
scripts/anibon-analyzer.py | Pre-flight: gaps, categories, byte sizes |
scripts/detect_signals.py | TF-IDF signal + knowledge file matching |
scripts/detect_boundaries.py | Detect topic boundaries (feeds --topic-json in Step 9) |
scripts/align_live_chat.py | Slice LiveChat event feed to per-transcript-chunk logs (Step 3.5) |
scripts/analyze_555.py | Detect Thai-laugh/meme pulses from aligned LiveChat → per-chunk mood verdict (Step 3.7) |
scripts/validate_mood.py | Verify mood-bearing timestamps honour mood_555 verdicts (Step 11.5) |
../anibon-livechat-analysis/scripts/parse_live_chat.py | Parse .live_chat.json to event feed (Step 3.5) |
../anibon-livechat-analysis/scripts/extract_visual_livechat.py | Extract burned-in on-screen LiveChat via Gemini vision proxy when .live_chat.json is missing (Step 3.5) |
scripts/merge_timestamps.py | Combine + sort subagent outputs |
scripts/process_chunks_local.py | Local LLM sequential chunk runner via LM Studio / llama.cpp OpenAI endpoint |
scripts/audit_gaps.py | Gap audit (NO GAPS rule) + gap→chunk mapping (Step 8.5) |
scripts/pack_timestamps.py | Byte-limited section packing (supports --break-at, --topic-json) |
scripts/check_sections.py | Validate byte cap + ASR garbles |
scripts/validate_part_coherence.py | Cross-reference game names vs signals |
scripts/validate_tags.py | Validate timestamp tag vocabulary |
../cleaning-auto-transcripts/scripts/clean_garbled_english.py | Normalize Thai-Whisper garbled English (Step 3) |
../cleaning-auto-transcripts/scripts/clean_transcript.py | Raw json3 cleaner (called by prepare_video) |
../anibon-world-identity/scripts/fetch_story_ref.py | Fetch/cache story synopses (user consent for websearch) |
../anibon-world-identity/scripts/align_ref_timeline.py | Align reference SRT timestamps with chunks |
../anibon-world-identity/scripts/fetch_fgo_db.py, fetch_ygo_db.py | Build card databases (World Identity) |
Iron Rules
- Use named agents — Step 7 MUST use
invoke_subagent("anibon-chunk-timestamper")per chunk. Step 8.6 MUST useinvoke_subagent("anibon-garbled-notes"). Step 9 MUST useinvoke_subagent("anibon-summarizer"). Never substitute a generic Task/self agent. - STRICT SUBAGENT BATCHING (4–6 RECOMMENDED) — Process in controlled batches of 4–6 subagents (max 8 with
Model: "flash"), wait for completion, then proceed to the next batch. Never launch 10+ subagents simultaneously on heavy prompt jobs. - FLASH MODEL TIER FOR CHUNKS — Use
Model: "flash"for chunk timestamper subagents to ensure fast execution and avoid API rate limits. - NO HEURISTIC / REGEX FALLBACKS — Never fall back to heuristic text-generation scripts if subagents hit errors or rate limits. All timestamps MUST be generated by authentic
anibon-chunk-timestampersubagent runs reading real transcript XML and LiveChat logs. - Use detect_signals.py — TF-IDF only. No ad-hoc grep/inline scanning.
- Don't read chunks yourself — subagents read XML. Inject signals.json data into prompts.
- ONE FILE — single
.mdwith═══section blocks. Nopart1.md. - NO GAPS — max 10 min between timestamps unless verified silent.
- INTRO BREAKDOWN — intro >10 min → break into 3-5 min sub-topic milestones.
- NO AD-HOC TIMESTAMPS — only via subagent pipeline →
merge_timestamps.py→anibon-summarizer. - READ BOTH SIDES — subagents must read the ENTIRE transcript chunk AND its LiveChat log (when present) before writing any timestamp. Situation + emotion come from both talks and chat, never from
primary_topicalone. - HONOUR THE MOOD VERDICT — when
mood_555.jsonexists, inject each chunk'stoneguidance (mood + suggested verbs) into the subagent prompt. The AI keeps its own first-verb choice, but must not flatline a chat-laugh/hype peak into a calm factual verb. - NON-SPOILER GACHA POLICY — Never spoil whether the streamer won or lost a gacha pull in the timestamp description. Focus on anticipation, the featured banner/character, and chat interactions.
- 18+ / RULE 34 TONE INTEGRITY — Do not trivialize adult fanart or Rule 34 commentary under generic comedic tags (
[Reaction] ฮา...). Use[Talk]with mature, direct, and accurate summaries. - PROPER NOUN & GAME TITLE INTEGRITY — When processing garbled notes (Step 8.6), NEVER map legitimate external game titles (e.g. MARVEL Tōkon: Fighting Souls, Alien: Isolation, TMNT: The Last Ronin), brand names, or common English phrases (e.g. where we meet) as noise patterns. Unconfirmed proper nouns must remain
correct: nullfor human review rather than being forced into generic Thai terms. - PROPER NOUN IN EVERY STAMP — Every timestamp must name its specific proper noun (e.g. Wuthering Waves, Zelda, น้องเนเน่ AGT, Bleach). Never use vague pronouns ("เกมนี้", "น้องคนนั้น", "ค่ายนี้"). The summarizer must NEVER drop proper nouns; trim adjectives or emotional filler instead.