Skill: yumyumtum/yumnb (version 0.1.1)

--- name: yumnb description: "Yum NoteBook — a local-first NotebookLM alternative for AI agents, built for real source capture. Ingest a web URL, YouTube video, or screenshot, then generate (1) AI summary, (2) dual-host talk-show MP3 (edge-tts), (3) slide deck (image/table/bullet/flowchart) and optionally upload artifacts to OneDrive/Google Drive/S3/etc. and post a notification to Slack/Discord/Teams. Language and cloud destination are user-configurable; defaults to English with male+female English hosts. Use when: yumnb, study notes, summarize this link, turn this video into notes, help me understand this article." argument-hint: "URL | YouTube link | path to screenshot (and optional --title / --language)" --- # Yum NoteBook (yumnb) — Source → Summary + Talk-show + Slides > **A local-first NotebookLM alternative for AI agents, built for real source capture.** ## What It Does Given a source (URL / YouTube / screenshot / raw text), creates **one folder per request** under `<output_dir>/<YYYYMMDD-HHMM-slug>/` containing: 1. **`source/`** — raw material (downloaded HTML, transcript, screenshot copy …) 2. **`summary.md`** — AI summary (one-liner / key points / facts / takeaways) 3. **`talkshow.txt` + `talkshow.mp3`** — dual-host script + MP3 (edge-tts) 4. **`deck.pptx`** — slide deck (bullets, tables, flow, images, summary) 5. **`links.json`** — record of what was generated and any share links This “one request = one folder” model is intentional: many such folders can accumulate into a local knowledge base that can be read, searched, narrated, and presented later. If a webhook is configured, a notification is posted to Slack / Discord / Teams Workflow. If `deliver.provider` is configured, yumnb can also push the finished outputs directly to an IM/chat surface through OpenClaw / Hermes (Telegram / Discord / Teams / Slack / etc.). You can position yumnb as a local-first, polite alternative to NotebookLM: it keeps notebooks and generated artifacts as ordinary local files by default, then only uploads or delivers them if you explicitly configure that. ## Two Ways to Run ### A. Fully-automatic (built-in AI provider) Configure `ai.provider` in `config.yaml` (openai / anthropic / gemini / ollama / cli) and run: ```bash python -m yumnb auto "<URL or path>" [--title "short name"] ``` This runs ingest → AI summary → AI slide-plan → TTS → PPT → publish in one shot. ### B. Step-by-step (agent-driven — you bring your own LLM) If you're driving this from an agent CLI (GitHub Copilot CLI, Claude Code, Cursor, Aider, …), set `ai.provider: none` and call the subcommands individually. The agent reads the source, writes `summary.md` and `deck.json` itself, then asks yumnb to render TTS / PPT / publish. ```bash # 1) Pull raw material python -m yumnb ingest "<URL>" [--title "..."] # → prints the note folder path # 2) (Agent writes <folder>/summary.md following the schema in README) # 3) Render dual-host MP3 from a talkshow script the agent wrote python -m yumnb tts "<folder>/talkshow.txt" --output "<folder>/talkshow.mp3" # 4) Render PPT from a deck.json the agent wrote python -m yumnb ppt "<folder>/deck.json" --output "<folder>/deck.pptx" # 5) Finalize + optional webhook / IM delivery python -m yumnb publish "<folder>" ``` ## Schemas the Agent Writes ### `summary.md` ```markdown # <title> > **Source**: <url or file> > **Type**: youtube|url|image|text > **Length**: <duration or word count> ## 🎯 One-line summary ## 📌 Key points (3-5) ## 🔑 Facts / data ## 💡 Takeaways ## 🤔 Open questions ``` ### `deck.json` (rendered to `deck.pptx`) ```json { "title": "Deck title", "subtitle": "Source / date", "slides": [ {"type": "title", "title": "...", "subtitle": "..."}, {"type": "bullets", "title": "...", "bullets": ["...", "..."]}, {"type": "table", "title": "...", "headers": ["A","B"], "rows": [["1","2"]]}, {"type": "flow", "title": "...", "steps": ["Step 1","Step 2","Step 3"]}, {"type": "image", "title": "...", "image_path": "/abs/path.png", "caption": "..."}, {"type": "two_column", "title": "...", "left": "bullet text", "image_path": "..."}, {"type": "summary", "title": "...", "text": "..."} ] } ``` Recommended: **5–12 slides** — title, 1-2 overview, 3-6 main (bullets/table/ flow/image), 1 summary. Reuse images from `source/` (YouTube thumbnail, HTML hero image, original screenshot). ### `talkshow.txt` Lines tagged with `[<SpeakerName>]` where `<SpeakerName>` matches a voice configured in `config.yaml` → `tts.voices`. Example: ``` [HostA] Welcome to the show — today we're chewing on… [HostB] And by chewing I mean ruthlessly mocking, right? [HostA] Pretty much. ``` ## Prerequisites - Python 3.9+ - Preferred first-run: `./scripts/bootstrap.sh` - Or manual: `pip install -r requirements.txt` - Plus the AI SDK matching your provider (only one): `openai` / `anthropic` / `google-generativeai` / `ollama` — or none if you use `provider: cli` / `none`. ## Notes - `edge-tts` uses Microsoft's free online voices. No API key required. - The intro/outro jingle is generated procedurally in pure Python — no external assets bundled. - YouTube ingest order is: yt-dlp manual subtitles → yt-dlp auto subtitles → `youtube-transcript-api` fallback → description-only fallback. - This skill carries no platform/tenant/organization-specific defaults. All endpoints and credentials come from `config.yaml` or environment variables (`YUMNB_*`, `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, etc.). - Direct IM delivery is channel-agnostic: configure `deliver.provider: openclaw` (or `hermes`) plus `deliver.openclaw.channel` + `target` to send the finished note to Telegram, Discord, Teams, Slack, and other supported surfaces via the local bridge. ## Language `config.yaml` → `language` (default `en`). Influences both AI prompt language and the default TTS voice pair. Override per-run with `--language en|zh|ja|es|fr|de|...`. Built-in default voice pairs (male + female, edge-tts): | `language` | HostA (male) | HostB (female) | | ---------- | ------------------------- | ------------------------- | | `en` | `en-US-AndrewNeural` | `en-US-AvaNeural` | | `zh` | `zh-CN-YunyangNeural` 云飞 | `zh-CN-XiaoxiaoNeural` 小晓 | | `ja` | `ja-JP-KeitaNeural` | `ja-JP-NanamiNeural` | | `es` | `es-ES-AlvaroNeural` | `es-ES-ElviraNeural` | | `fr` | `fr-FR-HenriNeural` | `fr-FR-DeniseNeural` | | `de` | `de-DE-ConradNeural` | `de-DE-KatjaNeural` | Override any pair (or add new languages) under `tts.language_voices`. Setting `tts.voices` directly always wins. ## Cloud upload (OneDrive / Google Drive / S3 / Dropbox / …) `config.yaml` → `upload.provider: rclone` makes `publish` upload the generated mp3 / pptx / summary to your configured cloud and inline the shareable URLs in `links.json` and the notification payload — so users get one-click mp3 + ppt links instead of local `file://` URIs. ```yaml upload: provider: rclone rclone: remote: "onedrive:yumnb" # or gdrive:yumnb, s3:bucket/yumnb, etc. share: true ``` Set it up once with `rclone config` (see https://rclone.org). yumnb delegates everything to rclone so the same skill works with every backend rclone supports.

path: LICENSE
content: MIT License

Copyright (c) 2026 yumnb contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


path: RELEASE_NOTES_v0.1.0.md
content: # yumnb v0.1.0 — Local-first Notebook Packet Generator

First public release of **yumnb**.

## Highlights

- Turn a URL, YouTube video, screenshot, or block of text into a local notebook folder
- Generate:
  - `summary.md`
  - `talkshow.txt`
  - `talkshow.mp3`
  - `deck.json`
  - `deck.pptx`
  - `links.json`
- YouTube ingest with subtitle fallback order:
  - manual subtitles
  - auto subtitles
  - `youtube-transcript-api`
  - description-only fallback
- Refactored into package modules with compatibility shims for older `scripts/*.py` entrypoints
- Bootstrap script for easier first-run setup
- Smoke tests for core local flows
- Friendlier auto-mode error messages when AI providers are not configured
- Channel-agnostic delivery support via OpenClaw / Hermes
  - Telegram
  - Discord
  - Slack
  - Teams
  - other supported OpenClaw surfaces
- Positioned as a **local-first, polite alternative to NotebookLM**

## Design intent

yumnb is for people who want a notebook workflow that stays file-based and local by default. Sources, summaries, scripts, slides, and generated artifacts live in ordinary folders unless upload / notify / deliver are explicitly enabled.


path: RELEASE_NOTES_v0.1.1.md
content: # yumnb v0.1.1 — Positioning + README polish

This patch release tightens yumnb's public positioning and documentation.

## What's new

- New tagline:
  - **A local-first NotebookLM alternative for AI agents, built for real source capture.**
- README now emphasizes:
  - one request = one notebook folder
  - user-facing flow instead of internal implementation flow
  - local-first storage and opt-in external delivery
  - reliable source extraction for web pages and YouTube URLs
- Simplified top-of-page diagram for easier reading
- Added better GitHub / ClawHub page presentation
  - badges
  - concise tables
  - clearer artifact explanations

## Why this matters

yumnb is not just a summarizer. It is meant to help AI agents build a local, inspectable, reusable notebook library with notes, audio, and slides — while being more transparent about source capture than many hosted notebook tools.


path: config.example.yaml
content: # yumnb configuration — copy to config.yaml and edit
# All keys are optional. Environment variables (YUMNB_*) override file values.

# ── Where to put generated notes (one sub-folder per item) ──────────────────
output_dir: ./notes

# ── Output language ────────────────────────────────────────────────────────
# Drives AI prompts (summary / talk-show / deck) AND the default TTS voice
# pair. Override per run with `--language en|zh|ja|es|fr|de|...`.
# Built-in default voice pairs ship for: en, zh, ja, es, fr, de.
# Add your own under tts.language_voices.<lang> below.
language: en

# ── AI provider for summary + slide-plan generation ────────────────────────
# Pick ONE backend. See README "AI providers" for details.
ai:
  # Options: openai | anthropic | gemini | ollama | cli | none
  #   - "none" / unset: skill only does ingest/tts/ppt mechanics; you (or
  #     another agent like Copilot CLI / Claude Code) write summary.md and
  #     deck.json by hand.
  # Default is `none` so first-run never hard-fails just because API keys are missing.
  provider: none

  # ── openai (also works with Azure OpenAI + any OpenAI-compatible API) ──
  openai:
    # [REDACTED_SECRET]        # or set env OPENAI_API_KEY
    model: gpt-4o-mini
    # base_url: https://api.openai.com/v1
    # base_url: http://localhost:11434/v1   # e.g. Ollama / LM Studio in OAI mode

  # ── anthropic ─────────────────────────────────────────────────────────
  anthropic:
    # [REDACTED_SECRET]
    model: claude-3-5-sonnet-latest

  # ── gemini ────────────────────────────────────────────────────────────
  gemini:
    # [REDACTED_SECRET]
    model: gemini-1.5-flash

  # ── ollama (local) ────────────────────────────────────────────────────
  ollama:
    host: http://localhost:11434
    model: qwen2.5:7b

  # ── cli: shell out to any agent CLI (Copilot CLI, Claude Code, etc.) ──
  # The CLI receives the prompt on stdin and must print the answer to stdout.
  cli:
    # Example: GitHub Copilot CLI
    # command: ["copilot", "--allow-tool", "shell", "-p", "-"]
    # Example: Anthropic Claude Code
    # command: ["claude", "-p"]
    # Example: aider in plain mode
    # command: ["aider", "--no-auto-commits", "--message", "-"]
    command: ["cat"]
    timeout_seconds: 300

# ── Text-to-speech ─────────────────────────────────────────────────────────
tts:
  enabled: true
  # `voices` (explicit) ALWAYS wins. If left empty, yumnb falls back to the
  # pair under `language_voices.<active_language>`. If even that's missing,
  # the built-in English pair is used.
  voices: {}
  # Map speaker tag (used in scripts as [TagName]) → edge-tts voice + rate.
  # See `edge-tts --list-voices` for the full catalog.
  language_voices:
    en:
      HostA: { voice: en-US-AndrewNeural, rate: "+0%" }   # male
      HostB: { voice: en-US-AvaNeural,    rate: "+0%" }   # female
    zh:
      云飞: { voice: zh-CN-YunyangNeural,  rate: "+10%" }
      小晓: { voice: zh-CN-XiaoxiaoNeural, rate: "+10%" }
    ja:
      HostA: { voice: ja-JP-KeitaNeural,  rate: "+0%" }
      HostB: { voice: ja-JP-NanamiNeural, rate: "+0%" }
    es:
      HostA: { voice: es-ES-AlvaroNeural, rate: "+0%" }
      HostB: { voice: es-ES-ElviraNeural, rate: "+0%" }
    fr:
      HostA: { voice: fr-FR-HenriNeural,  rate: "+0%" }
      HostB: { voice: fr-FR-DeniseNeural, rate: "+0%" }
    de:
      HostA: { voice: de-DE-ConradNeural, rate: "+0%" }
      HostB: { voice: de-DE-KatjaNeural,  rate: "+0%" }
  jingle: true            # add a generated intro/outro chime
  # custom_jingle_mp3: ./assets/my_jingle.mp3   # overrides generated chime

# ── Cloud upload (optional, but recommended) ───────────────────────────────
# After `publish`, push generated artifacts to a cloud destination and use
# the resulting shareable URLs in links.json + the notification payload —
# so users get clickable mp3 / pptx links in one shot instead of file:// URIs.
#
# yumnb is provider-agnostic and delegates to rclone (https://rclone.org),
# which supports OneDrive, Google Drive, S3, Dropbox, Box, pCloud, WebDAV,
# and ~50 more backends. Run `rclone config` once to authenticate, then
# reference your remote by name below as `<remote>:<folder>`.
#
# Examples:
#   onedrive:yumnb           Microsoft OneDrive (personal or business)
#   gdrive:yumnb             Google Drive
#   s3:my-bucket/yumnb       AWS S3 / Cloudflare R2 / MinIO
#   dropbox:yumnb            Dropbox
upload:
  provider: none           # none | rclone | onedrive_graph
  # ── onedrive_graph: reuse tommy-talkshow's onedrive_upload.py ─────────
  # Uploads via Edge SSO (no rclone, no client secret) to OneDrive for
  # Business / SharePoint and returns an org sharing link. Requires the
  # companion `tommy-talkshow` skill to be installed locally.
  onedrive_graph:
    # Absolute path to tommy-talkshow's onedrive_upload.py.
    # Supports ~ and ${ENV} expansion. Leave unset to disable this provider.
    # Example (Windows / Linux / macOS):
    #   uploader_path: ~/.copilot/skills/tommy-talkshow/scripts/onedrive_upload.py
    uploader_path: ""
    folder: yumnb             # remote folder name under your OneDrive root
    per_note_subfolder: true  # upload to <folder>/<note-slug>/<file>
    # base_url: optional SharePoint site base URL override (e.g.
    #   https://contoso-my.sharepoint.com/personal/<user>_contoso_com)
    base_url: ""
  rclone:
    remote: ""             # e.g. "onedrive:yumnb"
    rclone_bin: rclone     # path to the rclone binary
    share: true            # call `rclone link` to fetch a public URL
    per_note_subfolder: true  # upload to <remote>/<note-folder>/<file>
    extra_args: []         # passed to every `rclone copyto` call
  files: [talkshow.mp3, deck.pptx, summary.md]

# ── Notification webhook (optional) ────────────────────────────────────────
# After `yumnb publish`, post a simple JSON payload with title + links to a
# webhook. Works with Slack, Discord, generic HTTP receivers, and many Teams
# Workflows. Set to null to disable.
notify:
  webhook_url: null
  # Pick a payload style matching your destination.
  # Options: slack | discord | teams_workflow | generic
  style: generic

# ── Direct delivery to IM / chat surfaces (optional) ──────────────────────
# This is separate from `notify` webhooks.
#
# Use this when you want yumnb itself to push outputs into a chat/channel via
# the local OpenClaw / Hermes bridge, instead of only writing files / links.
#
# Supported provider today:
#   - openclaw  (alias: hermes)
#
# Because the underlying bridge is channel-aware, the SAME yumnb config shape
# can target Telegram, Discord, Slack, Microsoft Teams, etc. by changing only
# `channel` + `target`.
deliver:
  provider: none          # none | openclaw | hermes
  openclaw:
    binary: openclaw
    channel: ""          # telegram | discord | slack | msteams | ...
    target: ""           # chat id / channel id / user id depending on channel
    account: ""
    reply_to: ""
    thread_id: ""
    silent: false
    force_document: false
    captions: true
    send_text: true       # send a summary text message
    send_files: true      # send selected local artifacts as media/files
    dry_run: false
    timeout_seconds: 120
  files: [talkshow.mp3, deck.pptx]


path: scripts/__init__.py
content: """yumnb scripts package."""


path: scripts/ai_provider.py
content: """Compatibility wrapper for legacy imports.
Canonical implementation now lives at ``yumnb.ai_provider``.
"""

from yumnb.ai_provider import *  # noqa: F401,F403


Security scan verdicts — ClawScan: clean | static analysis: suspicious | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)