{"owner":"steipete","repo":"summarize","hasSkills":true,"totalSkillsCount":11,"totalTokensCount":10621,"categories":["anthropic-skill","root-instruction","command-prompt","plugin-manifest"],"hasMcp":false,"mcpConfig":null,"found":[".agents/skills/summarize/SKILL.md",".agents/skills/summarize/agents/openai.yaml","AGENTS.md","docs/commands/daemon.md","docs/commands/index.md","docs/commands/refresh-free.md","docs/commands/slides.md","docs/commands/summarize.md","docs/commands/transcriber.md","docs/openai.md","packages/core/README.md"],"skills":{".agents/skills/summarize/SKILL.md":"---\nname: summarize\ndescription: \"Summarize CLI: URLs, files, YouTube, transcripts, media, extraction, and JSON output.\"\n---\n\n# Summarize\n\nUse the `summarize` CLI as the canonical interface. Prefer a released binary on `PATH`; inside this repository, use `pnpm -s summarize` for the current checkout.\n\n## Start\n\n1. Confirm the command and current contract:\n\n   ```bash\n   summarize --version\n   summarize --help\n   ```\n\n2. Inspect model/provider readiness when a summary needs an LLM:\n\n   ```bash\n   summarize status\n   summarize status --json\n   ```\n\n3. Run the narrowest workflow below. Quote URLs and paths. Add `--timeout 2m` for slow remote or media inputs.\n\nNever print, request, or copy API-key values. `summarize status` reports availability without exposing secrets.\n\n## Summarize\n\nWeb page or remote document:\n\n```bash\nsummarize \"https://example.com/article\"\nsummarize \"https://example.com/report.pdf\" --length short\n```\n\nLocal file or stdin:\n\n```bash\nsummarize \"./report.pdf\"\nsummarize \"./recording.m4a\"\nprintf '%s\\n' \"Long text to summarize\" | summarize -\n```\n\nUse `--plain` for unrendered Markdown/text. Use `--language`, `--length`, `--prompt`, or `--prompt-file` only when the task requires an override. Use `--cli codex`, `--cli claude`, or another installed CLI provider when the user requests that provider or no direct API provider is configured.\n\n## Extract without a summary\n\nUse `--extract` to stop after extraction or transcription:\n\n```bash\nsummarize \"https://example.com/article\" --extract --format md\nsummarize \"./report.pdf\" --extract --format md\nsummarize \"https://youtu.be/VIDEO_ID\" --extract --format md\n```\n\n`--extract` does not support stdin. Extraction can still call configured transcription, OCR, Firecrawl, or Markdown services; it only skips the final summary call. `--markdown-mode llm` also invokes an LLM to reshape extracted text.\n\n## YouTube, audio, and video\n\nDefault transcript selection:\n\n```bash\nsummarize \"https://youtu.be/VIDEO_ID\"\nsummarize \"https://youtu.be/VIDEO_ID\" --extract --format md --timestamps\n```\n\nUse `--youtube web` to require web captions or `--youtube yt-dlp` to require the download/transcription path. Keep `auto` unless the user needs a specific source.\n\nLocal or remote audio/video:\n\n```bash\nsummarize \"./interview.mp3\" --extract\nsummarize \"./interview.mp4\" --extract --timestamps\nsummarize \"./interview.mp3\" --extract --diarize\n```\n\n`--transcriber auto` is the default. Use an explicit transcriber only when requested or diagnosing a provider. Diarization may require configured ElevenLabs or OpenAI access. Speaker identification is a separate opt-in step; do not infer identities without evidence.\n\nFor slides:\n\n```bash\nsummarize \"https://youtu.be/VIDEO_ID\" --slides\nsummarize \"./talk.mp4\" --slides --extract\n```\n\nSlide extraction may require `yt-dlp`; OCR requires `tesseract`.\n\n## JSON for automation\n\nUse JSON when another command or agent will parse the result:\n\n```bash\nsummarize \"https://example.com\" --json --metrics off > result.json\njq -r '.summary // .extracted.content // empty' result.json\n```\n\nThe stable top-level envelope contains `input`, `env`, `extracted`, `prompt`, `llm`, `metrics`, and `summary`. `summary` or `llm` can be `null` when extraction or a no-model path handles the input. In `--extract --json` mode, read extracted text from `.extracted.content`.\n\nJSON stays on stdout. Progress, warnings, and finish metrics stay on stderr. Do not merge stderr into stdout before parsing. Use `--metrics detailed` only when the task needs usage details.\n\n## Configuration and dependencies\n\nPrecedence: CLI flags, process environment, `~/.summarize/config.json`, built-in defaults. Prefer flags for one run; change config only when the user asks for a persistent default.\n\nUseful diagnostics:\n\n```bash\nsummarize status --verbose\nsummarize status --probe\nsummarize \"INPUT\" --verbose\n```\n\nPlain web summaries need no media tools. Media paths may use `ffmpeg`, `yt-dlp`, local Whisper/ONNX, or configured cloud transcription. Website fallback may use Firecrawl. Confirm the exact missing capability from the error before installing tools or changing config.\n\nInputs may be sent to the selected model, extraction, OCR, or transcription provider. For confidential material, confirm the approved provider or use an approved local path before running the command.\n\n## Verify\n\nAfter every run:\n\n- Require exit status `0`.\n- Require non-empty summary or extracted content.\n- For JSON, parse stdout with `jq` or another JSON parser.\n- For source-sensitive work, inspect `extracted`, `llm`, and stderr diagnostics rather than assuming the selected path.\n- Re-run the exact final command after changing provider, config, or flags.\n\nFor current option details, run `summarize --help` and read the repository documentation:\n\n- [Quickstart](../../../docs/quickstart.md)\n- [Main command](../../../docs/commands/summarize.md)\n- [Configuration](../../../docs/config.md)\n- [YouTube](../../../docs/youtube.md)\n- [Media](../../../docs/media.md)\n- [Extraction](../../../docs/extract-only.md)\n\n## Ownership\n\nThis file is the canonical agent workflow for the Summarize product. Keep generic agent workflows in `openclaw/agent-skills`; keep Summarize CLI behavior here. Downstream integrations should link to this file at a released tag or pinned commit and retain only their packaging or integration-specific notes. Do not maintain a second broad command guide downstream.\n",".agents/skills/summarize/agents/openai.yaml":"interface:\n  display_name: \"Summarize\"\n  short_description: \"Summarize URLs, files, and media with the CLI\"\n  default_prompt: \"Use $summarize to extract or summarize this URL, file, or media input.\"\n","AGENTS.md":"# Summarize Guardrails\n\n- Hard rule: single source of truth = `~/Projects/summarize`; never commit in `vendor/summarize` (treat it as a read-only checkout).\n- Note: multiple agents often work in this folder. If you see files/changes you do not recognize, ignore them and list them at the end.\n\n## Workspace layout (note)\n\n- Monorepo (pnpm workspace).\n- Packages:\n  - `@steipete/summarize` = CLI + UX (TTY/progress/streaming). Depends on core.\n  - `@steipete/summarize-core` (`packages/core`) = library surface for programmatic use (Sweetistics etc). No CLI entrypoints.\n- Versioning: lockstep versions; publish order: core first, then CLI (`scripts/release.sh` / `RELEASING.md`).\n- Homebrew/core formula is not owned here; BrewTestBot autobumps releases about every 3h. Do not block or manually manage it; ship and continue.\n- Chrome Web Store: every release must upload the matching `dist-chrome/summarize-chrome-extension-v<version>.zip` to item `cejgnmmhbbpdmjnfppjdfkocebngehfg`, submit it for review with automatic publishing, and verify the exact pending/published version. Skip only when every shipped change is daemon-side and the packaged extension/companion contract is unchanged.\n- Dev:\n  - Build: `pnpm run build` (builds core first; also runs during install via `prepare`)\n  - Gate: `pnpm run check`\n  - Import from apps: prefer `@steipete/summarize-core` to avoid pulling CLI-only deps.\n- Dependencies: stable releases need a 7-day stabilization delay before adoption; prereleases remain excluded unless already adopted.\n- Daemon: restart with `pnpm summarize daemon restart`; verify via `pnpm summarize daemon status`.\n- Rebuild (extension + daemon): run **both** in order:\n  1. `pnpm -C apps/chrome-extension build`\n  2. `pnpm summarize daemon restart`\n- Extension tests:\n  - `pnpm -C apps/chrome-extension test:chrome` = supported automated path.\n  - Firefox Playwright extension tests are not reliable (`moz-extension://` limitation); default `test:firefox` runs a temporary-install smoke test.\n  - Use `pnpm -C apps/chrome-extension test:firefox:force` only for explicit diagnostics.\n- Commits: use `committer \"type: message\" <files...>` (Conventional Commits).\n","docs/commands/daemon.md":"---\ntitle: summarize daemon\npermalink: /docs/commands/daemon.html\nkicker: command\nsummary: \"Manage the local daemon and Chrome Native Messaging bridge used by the Side Panel.\"\n---\n\n# `summarize daemon`\n\n```text\nsummarize daemon <subcommand> [options]\n```\n\nManages the local HTTP daemon and its browser integration. The daemon binds to `127.0.0.1` only and requires a shared bearer token. Chrome reaches it through an optional exact-ID Native Messaging host; Firefox retains its existing loopback integration. The daemon autostarts via the right service manager for your platform.\n\n| Platform | Service               |\n| -------- | --------------------- |\n| macOS    | LaunchAgent (launchd) |\n| Linux    | systemd user service  |\n| Windows  | Scheduled Task        |\n\nIf you only use the CLI, you don't need any of this.\n\n## Subcommands\n\n### `install`\n\nInstall or upgrade the autostart service, write `~/.summarize/daemon.json`, and register Chrome native host `com.steipete.summarize` on macOS/Linux.\n\n```bash\nsummarize daemon install --token <TOKEN>\nsummarize daemon install --token <TOKEN> --port 8787\nsummarize daemon install --token <TOKEN> --dev --extension-id <UNPACKED_ID>\n```\n\n`--token <token>` is **required** on first install; the extension prints one after pairing. Re-running `install` with a new token adds another paired browser instead of invalidating the old one. The native host manifest allows only Chrome Web Store extension ID `cejgnmmhbbpdmjnfppjdfkocebngehfg`.\n\n### `restart`\n\nRestart the autostart service. Useful after upgrading summarize or editing `daemon.json`.\n\n```bash\nsummarize daemon restart\n```\n\n### `status`\n\nProbe the autostart service, Chrome native-host registration, and the running daemon's health endpoint.\n\n```bash\nsummarize daemon status\n```\n\n### `uninstall`\n\nUnload the autostart service and remove the user-level Chrome native host. On macOS the daemon plist is moved to Trash so you can undo.\n\n```bash\nsummarize daemon uninstall\n```\n\n### `run`\n\nRun the daemon in the foreground. The autostart entry uses this internally; use it directly inside containers, on systems without launchd/systemd, or while debugging.\n\n```bash\nsummarize daemon run --port 8787\n```\n\n## Options\n\n`--port <n>`\n: TCP port. Default `8787`. For a non-default port, set the same value in the extension under **Options → Runtime → Daemon → Port**. The native host reads `daemon.json` and rejects mismatched requests.\n\n`--token <token>`\n: Bearer token. Required for `install`; also accepted by `run`, which adds it alongside the stored tokens for that run (required when no `daemon.json` exists). Stored in `~/.summarize/daemon.json` (mode `0600`).\n\n`--dev`\n: Install a service that runs `src/cli.ts` via Node's native TypeScript support from the current repo. Useful while hacking on the daemon — don't ship it to users.\n\n`--extension-id <id>`\n: With `--dev`, bind the native host to an unpacked Chrome extension ID. Production installs always use the exact Web Store ID.\n\n## HTTP endpoints\n\nThe daemon is documented in detail in [Chrome extension](../chrome-extension.md) and [Agent / daemon](../agent.md). At a glance:\n\n- `POST /v1/summarize` — start a run. Bearer-auth required. Returns `{ ok, id }` JSON (`coalesced: true` when it joins an in-flight run for the same request).\n- `GET /v1/summarize/{id}/events` — SSE stream of progress events and the final result for a run.\n- `GET /health` — health probe (used by `status`).\n\n## Files\n\n`~/.summarize/daemon.json`\n: Bearer token(s), port, and an env snapshot captured at install (includes provider API keys). Mode `0600`.\n\n`~/.summarize/daemon.log`\n: Rolling log written by the autostart service.\n\n## Notes\n\n- **Containers** — `install` starts the daemon for the current container session but does not register a Scheduled Task / unit. Run `summarize daemon run` from your entrypoint. Do not expose the port as a Chrome Native Messaging substitute.\n- **Token rotation** — running `install --token <NEW>` adds a new paired browser; old browsers keep working. Edit `daemon.json` by hand to revoke.\n- **Multiple installs** — only one daemon per user. Reinstall to upgrade; omitting `--port` preserves the configured port.\n- **Windows** — the npm-installed CLI still needs a packaged native-host `.exe`; do not route daemon traffic through the Direct-provider loopback grants as a workaround. Direct and Browser modes continue to work.\n\n## See also\n\n- [Chrome extension](../chrome-extension.md) — pairing flow + Side Panel UI.\n- [Agent / daemon](../agent.md) — automation surface.\n","docs/commands/index.md":"---\ntitle: Commands\npermalink: /docs/commands/\nkicker: reference\nsummary: \"Every summarize subcommand and flag, with examples.\"\n---\n\n# Command reference\n\n`summarize` is one binary with a handful of subcommands. The default subcommand is `summarize` itself — the one you use 99% of the time. The others wrap related tooling.\n\n## Subcommands\n\n- [`summarize`](summarize.md) — main command. Takes a URL, file, or stdin and produces a summary or extracted content.\n- [`summarize status`](../cli.md#cli-discovery) — print the selected model, enabled providers, and runtime status.\n- [`summarize slides`](slides.md) — extract scene-change keyframes from a YouTube URL, direct video URL, or local video file into PNGs (and optional OCR text). Standalone version of the `--slides` flag.\n- [`summarize transcriber`](transcriber.md) — set up local ONNX transcription (Parakeet, Canary). Prints the env vars you need.\n- [`summarize daemon`](daemon.md) — manage the local HTTP daemon that the Chrome Side Panel talks to. Subcommands: `install`, `restart`, `status`, `uninstall`, `run`.\n- [`summarize refresh-free`](refresh-free.md) — scan OpenRouter `:free` models, write working candidates to `~/.summarize/config.json`.\n- `summarize help [topic]` — print help for the CLI or a subcommand (`slides`, `status`, `daemon`, `transcriber`, `refresh-free`).\n\n## Output discipline\n\nAll subcommands keep the same output discipline — straight from gogcli's playbook so pipes and scripts stay parseable:\n\n- **stdout:** the result. Plain text, Markdown, JSON, or files (slides only).\n- **stderr:** progress, prompts, warnings, and errors.\n- `--json` produces a stable envelope on stdout.\n- `--no-color` strips ANSI; `--plain` skips ANSI/OSC rendering for Markdown.\n\n## Global behavior\n\nOnly two flags apply to every subcommand; the rest are per-command:\n\n| Flag                          | Where it works                                                                                                                             |\n| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |\n| `--locale <locale>`           | Everywhere. Interface language: `auto` plus the shipped UI locales (`SUMMARIZE_LOCALE` too).                                               |\n| `--help`                      | Everywhere (`summarize help <topic>` prints topic help).                                                                                   |\n| `-V`, `--version`             | `summarize`, `summarize slides`.                                                                                                           |\n| `--json`                      | `summarize`, `summarize slides`, `summarize status`.                                                                                       |\n| `--no-color`                  | `summarize`, `summarize status`, `summarize refresh-free`, `summarize transcriber`.                                                        |\n| `--theme <name>`              | `summarize`, `summarize slides`, `summarize transcriber` (`SUMMARIZE_THEME` env var also works).                                           |\n| `--verbose` / `--debug`       | `summarize`, `summarize slides`, `summarize refresh-free`, `summarize daemon`, `summarize transcriber`. `status` accepts `--verbose` only. |\n| `--metrics off\\|on\\|detailed` | `summarize` only.                                                                                                                          |\n| `--timeout <duration>`        | `summarize`, `summarize slides`.                                                                                                           |\n\n## Exit codes\n\n| Code  | Meaning                                                                     |\n| ----- | --------------------------------------------------------------------------- |\n| `0`   | Success.                                                                    |\n| `1`   | Any failure — usage errors, extraction, model, network, and timeouts alike. |\n| `130` | Interrupted by SIGINT (Ctrl+C).                                             |\n| `143` | Terminated by SIGTERM.                                                      |\n\n`summarize daemon` and `summarize transcriber` still exit `1` when the underlying service install (launchd, systemd, schtasks) fails; the platform's own error text is included in the message — check `--verbose` output for the raw error.\n","docs/commands/refresh-free.md":"---\ntitle: summarize refresh-free\npermalink: /docs/commands/refresh-free.html\nkicker: command\nsummary: \"Scan OpenRouter :free models and write working candidates to config.\"\n---\n\n# `summarize refresh-free`\n\n```text\nsummarize refresh-free [--runs 2] [--smart 3] [--min-params 27b]\n                       [--max-age-days 180] [--set-default] [--verbose]\n```\n\nProbes [OpenRouter](https://openrouter.ai)'s catalog for `:free` models, runs them on a small benchmark, and writes the working ones to `models.free` in `~/.summarize/config.json`. Useful when you want to use `--model free` without picking a specific OpenRouter slug.\n\nNeeds `OPENROUTER_API_KEY` in the environment.\n\n## What it does\n\n1. Pulls the OpenRouter model catalog.\n2. Filters to models tagged `:free` that meet `--min-params` and `--max-age-days`.\n3. Benchmarks every candidate once against a sanity prompt, then probes the shortlisted candidates `--runs` more times; ranks by `--smart` heuristics (latency, completion length, refusal rate).\n4. Writes the survivors to `models.free` in `~/.summarize/config.json`.\n5. With `--set-default`, also sets top-level `model` to `free`.\n\nAfter the run, `summarize \"https://example.com\" --model free` rotates through the saved list until one succeeds.\n\n## Flags\n\n`--runs <n>`\n: Extra refinement probes per shortlisted candidate after the initial benchmark run (`1 + --runs` total). `0` skips refinement. Default `2`.\n\n`--smart <n>`\n: How many top candidates to keep. Default `3`.\n\n`--min-params <size>`\n: Minimum parameter count. Accepts `7b`, `27b`, `70b`, etc. Default `27b`.\n\n`--max-age-days <n>`\n: Reject models older than N days based on OpenRouter's metadata. Default `180`.\n\n`--set-default`\n: Also set `model: \"free\"` at the top level of `~/.summarize/config.json`.\n\n`--verbose` / `--debug`\n: Per-candidate progress, timings, and rejection reasons on stderr.\n\n## Examples\n\n```bash\n# Quick refresh; keep the best 3 free models ≥27B, ≤180d old.\nsummarize refresh-free\n\n# Looser filter — accept smaller / older models.\nsummarize refresh-free --min-params 7b --max-age-days 365\n\n# Refresh and also set the default model.\nsummarize refresh-free --set-default\n\n# Verbose ranking output for debugging.\nsummarize refresh-free --runs 3 --smart 5 --verbose\n```\n\n## Output\n\n`~/.summarize/config.json` is updated in place. The relevant section ends up looking like:\n\n```json\n{\n  \"models\": {\n    \"free\": [\"openai/gpt-oss-120b:free\", \"z-ai/glm-4.6:free\", \"deepseek/deepseek-r1:free\"]\n  }\n}\n```\n\nA short summary of survivors and rejected candidates is printed on stderr. The only stdout line is the localized config-write confirmation, e.g. `Wrote /Users/you/.summarize/config.json (models.free)` — a sentence containing the path, not a bare path value.\n\nColor follows the rest of the CLI: `FORCE_COLOR=0` disables it, while a nonzero `FORCE_COLOR` takes precedence over `NO_COLOR`. Without an override, color requires a capable terminal.\n\n## See also\n\n- [LLM overview](../llm.md) — `--model` syntax, including `free`.\n- [Auto selection](../model-auto.md) — how `auto` picks across providers.\n- [Config](../config.md) — full schema for `~/.summarize/config.json`.\n","docs/commands/slides.md":"---\ntitle: summarize slides\npermalink: /docs/commands/slides.html\nkicker: command\nsummary: \"Extract scene-change keyframes from a video source into PNG files.\"\n---\n\n# `summarize slides`\n\n```text\nsummarize slides <source> [flags]\n```\n\nExtracts slide-shaped keyframes from a YouTube URL, direct video URL, or local video file using FFmpeg scene detection. Native ffmpeg is preferred; bundled FFmpeg WebAssembly is used when native `ffmpeg`/`ffprobe` are unavailable. Output is a directory of PNGs (and optional OCR text). This is the standalone form of the `--slides` flag on the main command — useful when you only want the slides without a summary.\n\n## Synopsis\n\n```bash\nsummarize slides \"https://youtu.be/...\"\nsummarize slides \"https://youtu.be/...\" --render auto\nsummarize slides \"https://youtu.be/...\" --slides-ocr -o ./out\nsummarize slides \"https://example.com/lecture.mp4\" --slides-max 12\nsummarize slides ./lecture.mp4 --slides-max 12\n```\n\n## Requirements\n\n- Bundled FFmpeg WebAssembly, or native `ffmpeg` on PATH for faster extraction and broader codec support.\n- `yt-dlp` on PATH for YouTube URLs.\n- `tesseract` on PATH for `--slides-ocr`.\n\nIf a required tool is missing, summarize prints a clear warning and exits non-zero.\n\n## Flags\n\n`--slides-ocr`\n: Run OCR on every extracted slide. Stores `ocrText` and `ocrConfidence` in `slides.json` and the JSON response.\n\n`--slides-dir <dir>`\n: Output base directory. Default: `./slides`. A per-video subfolder is created inside.\n\n`-o, --output <dir>`\n: Alias for `--slides-dir`.\n\n`--slides-scene-threshold <value>`\n: Scene detection threshold, `0.1`–`1.0`. Default `0.3`. Lower values detect more scenes (more slides); higher values are stricter.\n\n`--slides-max <count>`\n: Cap on extracted slides. Default `6`.\n\n`--slides-min-duration <seconds>`\n: Minimum gap between slides. Default `2`.\n\n`--render <mode>`\n: Inline render of thumbnails: `auto`, `kitty`, `iterm`, `none`. Default `none` — paths are printed instead.\n\n`--theme <name>`\n: Pick a CLI theme.\n\n`--timeout <duration>`\n: Per-operation timeout setting. Default `2m`; not an overall wall-clock deadline. yt-dlp downloads and FFmpeg scene detection allow at least `5m`, and individual extraction/probe steps have their own limits.\n\n`--no-cache`\n: Force re-download and re-extraction (bypasses both caches).\n\n`--json`\n: JSON envelope on stdout. Disables inline rendering.\n\n`--verbose` / `--debug`\n: Detailed progress on stderr.\n\n`-V`, `--version`\n: Print version and exit.\n\n## Output\n\nEach run writes a directory like:\n\n```text\nslides/<source-id>/\n  slide_0001_18.60s.png\n  slide_0002_42.20s.png\n  ...\n  slides.json\n```\n\nThe filenames include the slide index and timestamp. `slides.json` records the manifest, including OCR results when requested; OCR does not create separate text files. `ocrConfidence` uses a 0–1 scale.\n\nIn `--json` mode, stdout contains an envelope like this (additional extraction metadata omitted):\n\n```json\n{\n  \"ok\": true,\n  \"slides\": {\n    \"sourceUrl\": \"https://example.com/lecture.mp4\",\n    \"slidesDir\": \"/absolute/path/slides/<id>\",\n    \"slides\": [\n      {\n        \"index\": 1,\n        \"timestamp\": 18.6,\n        \"imagePath\": \"/absolute/path/slides/<id>/slide_0001_18.60s.png\",\n        \"ocrText\": \"Recognized slide text\",\n        \"ocrConfidence\": 0.92\n      }\n    ]\n  }\n}\n```\n\n## Inline rendering\n\n`--render auto` detects Kitty (`KITTY_WINDOW_ID`) and iTerm (`TERM_PROGRAM=iTerm.app`) and uses the matching image protocol. On unsupported terminals, slides are listed by path instead.\n\n## Examples\n\n```bash\n# Quick preview in iTerm/Kitty.\nsummarize slides \"https://youtu.be/...\" --render auto\n\n# Big lecture, more granular cuts.\nsummarize slides \"https://youtu.be/...\" \\\n  --slides-max 24 --slides-scene-threshold 0.2\n\n# Pipe-friendly JSON for an automation.\nsummarize slides \"https://youtu.be/...\" --json | jq '.slides.slides[].imagePath'\n\n# Force re-extraction after editing the source video.\nsummarize slides \"./talk.mp4\" --no-cache -o ./out\n```\n\n## See also\n\n- [Slides mode](../slides.md) — the inline `--slides` flag on the main command.\n- [Slides rendering flow](../slides-rendering-flow.md) — pipeline internals.\n","docs/commands/summarize.md":"---\ntitle: summarize\npermalink: /docs/commands/summarize.html\nkicker: command\nsummary: \"Main command. URL, file, or stdin → clean text → summary.\"\n---\n\n# `summarize`\n\n```text\nsummarize [input] [flags]\n```\n\nTakes a URL, local file path, or `-` for stdin and produces a summary. With `--extract`, prints cleaned content instead of summarizing; stdin is not supported in extract mode.\n\n## Synopsis\n\n```bash\nsummarize \"https://example.com/article\"\nsummarize ./report.pdf --model openai/gpt-5-mini\nsummarize \"https://youtu.be/...\" --slides --slides-ocr\npbpaste | summarize -\nsummarize \"https://example.com\" --extract --format md > clean.md\nsummarize \"https://example.com\" --json --metrics detailed\n```\n\n## Input\n\n- **URL** — http/https. YouTube, podcast hosts, generic articles, raw media.\n- **File path** — PDF, image, audio, video, plain text, Markdown, HTML.\n- **`-`** — read content from stdin (text or binary).\n\nIf `[input]` is omitted, summarize prints concise help and exits.\n\n## Flags\n\n### Extraction\n\n`--extract`\n: Print extracted content and exit. No LLM call. Supports URLs, YouTube/direct media, local audio/video, and local PDFs; `-` stdin is not supported. The `--extract-only` alias is hidden but still works.\n: Extraction can still use configured remote transcription, OCR, or Markdown providers for media/PDF inputs.\n\n`--format <format>`\n: `md`/`markdown` or `text`/`txt`/`plain`. Controls website extraction format and whether files are preprocessed to Markdown for model compatibility. Default: `text`. Default in `--extract` mode for URLs: `md`.\n\n`--firecrawl <mode>`\n: `off`, `auto`, `always`. `auto` falls back to Firecrawl when local extraction looks blocked or thin. Needs `FIRECRAWL_API_KEY`.\n\n`--preprocess <mode>`\n: `off`, `auto`, `always`. Default `auto`. Controls `markitdown` usage for files. `always` only affects file inputs.\n: Image-only PDFs can retry through OpenAI vision OCR when `OPENAI_API_KEY` is set. Set `MARKITDOWN_OCR_MODEL` to choose the OCR model, or `MARKITDOWN_OCR_DPI` to tune rendered page size.\n\n`--markdown-mode <mode>`\n: `off`, `auto`, `llm`, `readability`. For websites: HTML → Markdown strategy. For YouTube/transcripts: `llm` formats raw transcripts into clean Markdown with headings. The `--markdown` alias is hidden and deprecated.\n\n`--max-extract-characters <count>`\n: Cap printed characters in `--extract` mode. Default: unlimited.\n\n### YouTube / video\n\n`--youtube <mode>`\n: `auto`, `web`, `apify`, `yt-dlp`, `no-auto` (skip auto-generated captions). Default `auto`.\n\n`--transcriber <name>`\n: Select the local transcription stage: `auto`, `whisper`, `parakeet`, `canary`. Default `auto` — Groq still runs first when keyed, then local ONNX/`whisper.cpp`, then cloud fallbacks.\n\n`--video-mode <mode>`\n: `auto`, `transcript`, `understand`. `understand` prefers vision/video understanding when supported.\n\n`--embedded-video <mode>`\n: `auto`, `off`, `prefer`, `both`. Controls embedded YouTube handling on regular web pages: `off` keeps the article text only, `prefer` favors the video transcript, `both` combines labeled article + transcript sections. Default `auto` — uses only high-confidence primary embeds. See [Website mode](../website.md).\n\n`--timestamps`\n: Include timestamps in transcripts when available.\n\n`--diarize [provider]`\n: Add speaker labels to YouTube, local audio/video, or direct media URLs. Provider: `auto`, `elevenlabs`, or `openai`.\n\n`--identify-speakers` / `--no-identify-speakers`\n: Resolve generic diarization labels to names, or disable configured resolution for one run. Uses authoritative anchors and OpenAI GPT-5.5 context inference.\n\n`--speaker-profile <name>`\n: Select a reusable profile from `speakers.profiles` in the config file.\n\n`--speaker-at <timestamp=name>`\n: Name the speaker active at a timestamp. Repeat the flag for multiple speakers.\n\n`--remember-speakers`\n: Atomically persist resolved names, anchors, and a transcript-hash-guarded source mapping under the selected profile.\n\n### Slides\n\n`--slides [on|off]` / `--no-slides`\n: Extract slides from a YouTube URL, direct video URL, or local video file and render inline alongside the summary. Combine with `--extract` to interleave slides in the full transcript. See [Slides mode](../slides.md).\n: The optional value accepts boolean words (`on`/`off`, `true`/`false`, `yes`/`no`, `1`/`0`); anything else is rejected. Use `--no-slides` to disable slide extraction enabled in the config file for one run.\n\n`--slides-ocr` / `--no-slides-ocr`\n: Run OCR on extracted slides. Requires `tesseract`.\n: Use `--no-slides-ocr` to disable configured slide OCR while retaining slide extraction.\n\n`--slides-debug`\n: Print slide image paths instead of rendering inline (useful in non-image terminals).\n\n`--slides-dir <dir>`\n: Output directory base. Default `./slides`.\n\n`--slides-scene-threshold <value>`\n: Scene detection threshold, `0.1`–`1.0`. Default `0.3`.\n\n`--slides-max <count>`\n: Cap on extracted slides. Default `6`.\n\n`--slides-min-duration <seconds>`\n: Minimum gap between slides. Default `2`.\n\n### Summary control\n\n`--length <length>`\n: `short`, `medium`, `long`, `xl`, `xxl` (or `s`/`m`/`l`) or a character cap like `20000` or `20k`. Default `long`. Override globally via `output.length` in [Config](../config.md).\n\n`--force-summary`\n: Always run the LLM, even when extracted content is shorter than the requested length.\n\n`--language, --lang <language>`\n: `auto`, `en`, `de`, `english`, `german`, … Default `auto` (matches source). Configurable via `output.language`.\n\n`--locale <locale>`\n: CLI interface language: `auto` plus the shipped UI locales (`en`, `de`, `fr`, `es`, `it`, `pt-BR`, `nl`, `pl`, `ru`, `ja`, `zh-Hans`, `zh-Hant`, `ko`, `tr`). Default follows the system locale with English fallback. `SUMMARIZE_LOCALE` also works. See [Localization](../localization.md).\n\n`--prompt <text>` / `--prompt-file <path>`\n: Override the summary prompt. Content is appended after the override.\n\n### Models\n\n`--model <model>`\n: Model id. `auto`, `<config-preset>`, `cli/<provider>/<model>`, `xai/...`, `openai/...`, `nvidia/...`, `minimax/...`, `google/...`, `anthropic/...`, `zai/...`, `ollama/<model>` (local Ollama), `openclaw/<model>` (shorthand for `cli/openclaw/<model>`), or `openrouter/<author>/<slug>`. Default `auto`. See [LLM overview](../llm.md).\n\n`--cli [provider]`\n: Use a logged-in CLI provider: `claude`, `gemini`, `codex`, `agent`, `openclaw`, `opencode`, `copilot`, `agy`, `pi`, `devin`, `grok`. Equivalent to `--model cli/<provider>`. Without a value: enable CLI providers in auto-selection.\n\n`--thinking <effort>`\n: Reasoning effort. `none`, `low`, `medium`, `high`, `xhigh`, `max` (GPT-6 models). Aliases: `off`, `min`, `med`, `mid`, `x-high`, `extra-high`. Affects reasoning-capable models on the dispatched provider (OpenAI, Anthropic Claude 4+, pi CLI).\n\n`--service-tier <tier>`\n: OpenAI service tier. `default`, `fast`, `priority`, `flex`. Maps to `service_tier` on the request.\n\n`--fast`\n: Shortcut for OpenAI `service_tier=priority`. Same effect as `--service-tier fast`.\n\n`--max-output-tokens <count>`\n: Hard cap for LLM output tokens. Accepts `2000`, `2k`. Overrides provider defaults.\n\n`--retries <count>`\n: LLM retry attempts after timeouts or transient API failures. `0`–`5`. Default `1`.\n\n### Output\n\n`--json`\n: Structured JSON envelope on stdout. Includes prompt + metrics. Disables streaming.\n\n`--stream <mode>`\n: `auto`, `on`, `off`. Default `auto` (TTY-only). Disabled in `--json` mode.\n\n`--plain`\n: Keep raw text/Markdown — no ANSI/OSC rendering.\n\n`--no-color`\n: Disable ANSI colors.\n\n`--width <columns>`\n: Override terminal width for Markdown rendering. Default: auto-detect, max 120.\n\n`--theme <name>`\n: Pick a CLI theme. Run `summarize --help` for the list. Env: `SUMMARIZE_THEME`.\n\n### Cache\n\n`--no-cache`\n: Bypass the summary (LLM) cache. Media + transcript caches stay enabled.\n\n`--no-media-cache`\n: Disable the media download cache (`yt-dlp` outputs).\n\n`--cache-stats`\n: Print cache stats and exit.\n\n`--clear-cache`\n: Delete the cache database and exit.\n\nSee [Cache internals](../cache.md) for what's cached and where.\n\n### Diagnostics\n\n`--verbose`\n: Detailed progress on stderr.\n\n`--debug`\n: Alias for `--verbose`. Also defaults `--metrics` to `detailed`.\n\n`--metrics <mode>`\n: `off`, `on`, `detailed`. Default `on`. Adds a compact second-line breakdown on stderr when `detailed`.\n\n`--timeout <duration>`\n: Per-operation timeout for content fetching and LLM requests (not an overall wall-clock deadline). `30`, `30s`, `2m`, `5000ms`. Default `2m`.\n\n`-V`, `--version`\n: Print version and exit.\n\n## Examples\n\n```bash\n# Extracted plain text from a URL.\nsummarize \"https://example.com\" --extract\n\n# Extracted Markdown — prefers Firecrawl when configured.\nsummarize \"https://example.com\" --extract --format md\n\n# YouTube transcript as cleanly-formatted Markdown.\nsummarize \"https://www.youtube.com/watch?v=...\" \\\n  --extract --format md --markdown-mode llm\n\n# ElevenLabs diarization with verified speaker names.\nsummarize \"https://www.youtube.com/watch?v=...\" --extract \\\n  --diarize elevenlabs --identify-speakers \\\n  --speaker-profile my-podcast --speaker-at \"0:12=Host Name\" --remember-speakers\n\n# Inline slides + summary.\nsummarize \"https://www.youtube.com/watch?v=...\" --slides\n\n# Full transcript + inline slides.\nsummarize \"https://www.youtube.com/watch?v=...\" --slides --extract\n\n# Hard caps + a specific model.\nsummarize \"https://example.com\" \\\n  --length 20k --max-output-tokens 2k --timeout 2m \\\n  --model openai/gpt-5-mini\n\n# OpenAI fast tier with reasoning.\nsummarize \"https://example.com\" \\\n  --model openai/gpt-5.5 --fast --thinking medium\n\n# Config preset (alias defined in ~/.summarize/config.json).\nsummarize \"https://example.com\" --model mymodel\n\n# Strict JSON for scripts.\nsummarize \"https://example.com\" --json --verbose\n\n# Summarize the clipboard.\npbpaste | summarize -\n```\n\n## Environment\n\nThe provider keys and binary paths picked up at runtime are listed in [LLM overview](../llm.md#env). `SUMMARIZE_MODEL` overrides the default model selection; `SUMMARIZE_THEME` picks the theme; `SUMMARIZE_LOCALE` picks the interface language.\n\n## See also\n\n- [LLM overview](../llm.md) — how `--model` resolves to a provider.\n- [Website mode](../website.md), [YouTube](../youtube.md), [Media + podcasts](../media.md).\n- [Cache](../cache.md), [Firecrawl](../firecrawl.md).\n- [Config](../config.md) for persistent defaults.\n","docs/commands/transcriber.md":"---\ntitle: summarize transcriber\npermalink: /docs/commands/transcriber.html\nkicker: command\nsummary: \"Set up local ONNX transcription (Parakeet, Canary).\"\n---\n\n# `summarize transcriber`\n\n```text\nsummarize transcriber setup [--model parakeet|canary] [--theme <name>]\n```\n\nConfigures local ONNX transcription. The command **prints the env vars** you need to export — it doesn't write to your shell config. Once those vars are exported, `--transcriber auto` (or `SUMMARIZE_TRANSCRIBER=auto`) uses ONNX after Groq and before `whisper.cpp` and the remaining cloud fallbacks.\n\n## How auto picks a transcriber\n\nWhen `--transcriber auto` is set (default), summarize tries providers in this order:\n\n1. **Groq** — fastest cloud option. Needs `GROQ_API_KEY`.\n2. **Local ONNX** (Parakeet or Canary), then `whisper.cpp` — fully offline. ONNX needs the env vars from this command.\n3. **AssemblyAI / Gemini / OpenAI / FAL / Deepgram** — cloud fallbacks, in that order, gated by their respective API keys.\n\n`OPENAI_WHISPER_BASE_URL` changes the endpoint used by the OpenAI transcription stage; it is not a separate provider in the order above.\n\n## Subcommand\n\n### `summarize transcriber setup`\n\n`--model <name>`\n: `parakeet` (default) or `canary`. Picks which ONNX model the printed snippet targets.\n\n`--theme <name>`\n: CLI theme override.\n\nThe output is a labelled, copy-pasteable block of `export` lines for your shell. Re-run with the other model to switch.\n\n## Environment\n\nSet by the printed snippet:\n\n`SUMMARIZE_ONNX_PARAKEET_CMD`\n: Command to run Parakeet ONNX transcription. Use `{input}` as the audio-file placeholder.\n\n`SUMMARIZE_ONNX_CANARY_CMD`\n: Command to run Canary ONNX transcription. Use `{input}` as the audio-file placeholder.\n\n`SUMMARIZE_TRANSCRIBER`\n: Optional. Select the local stage with `auto`, `whisper`, `parakeet`, or `canary` without passing `--transcriber` every time.\n\n## Examples\n\n```bash\n# Default: Parakeet.\nsummarize transcriber setup\n\n# Set up Canary instead.\nsummarize transcriber setup --model canary\n\n# After exporting the printed vars:\nsummarize \"https://podcasts.apple.com/.../episode-...\" --transcriber parakeet\n```\n\n## See also\n\n- [ONNX transcription](../nvidia-onnx-transcription.md) — how to actually install the model + runtime.\n- [Transcript provider flow](../transcript-provider-flow.md) — full selection waterfall.\n","docs/openai.md":"---\ntitle: \"OpenAI\"\nkicker: \"models\"\nsummary: \"OpenAI model usage and flags.\"\nread_when:\n  - \"When changing OpenAI integration.\"\n---\n\n# OpenAI models\n\nUse OpenAI directly by choosing an `openai/...` model id.\n\nFor the full model/provider matrix, see `docs/llm.md`.\n\n## GPT-6\n\nUse the documented model ids: `openai/gpt-6-astra`, `openai/gpt-6-sol`, `openai/gpt-6-luna`, or `openai/gpt-6.1-sol`.\nSummarize uses the Responses API by default for direct OpenAI text and image requests, including streaming, and for PDF inputs. `OPENAI_USE_CHAT_COMPLETIONS=1` still selects Chat Completions for text and images.\nReasoning requests omit `temperature`, which GPT-6 rejects. GPT-6 Sol and Luna preserve temperature when explicitly using `--thinking none`; Astra and GPT-6.1 Sol require reasoning.\n\n```sh\nsummarize https://summarize.sh/ --model openai/gpt-6-astra --thinking medium --fast\nsummarize https://summarize.sh/ --model openai/gpt-6-sol --thinking medium\nsummarize https://summarize.sh/ --model openai/gpt-6-luna --thinking low\nsummarize https://summarize.sh/ --model openai/gpt-6.1-sol --thinking max\n```\n\nThese explicit model ids do not change the default model or existing presets.\nThe model picker and built-in pricing catalog include all four models. Standard input/output\nprices per million tokens are $10/$50 for Astra, $2/$10 for Sol and GPT-6.1 Sol, and $0.10/$0.50 for Luna.\nCost estimates use these standard rates; they do not include cache discounts, cache writes,\nfast/flex service tiers, or long-context premiums. See [OpenAI pricing](https://developers.openai.com/api/docs/pricing).\nAll four GPT-6 models support `low`, `medium`, `high`, `xhigh`, and `max`. Summarize accepts `max` only for these documented model ids.\nAn unsupported `--thinking none` request for Astra or GPT-6.1 Sol fails locally before sending an API request.\nSee OpenAI's [GPT-6 guide](https://developers.openai.com/api/docs/guides/latest-model) and model pages for [Astra](https://developers.openai.com/api/docs/models/gpt-6-astra), [Sol](https://developers.openai.com/api/docs/models/gpt-6-sol), [Luna](https://developers.openai.com/api/docs/models/gpt-6-luna), and [GPT-6.1 Sol](https://developers.openai.com/api/docs/models/gpt-6.1-sol).\n\n## Fast mode\n\nFast mode is a service tier, not a model id. Prefer flags:\n\n```sh\nsummarize URL --model openai/gpt-5.5 --fast --thinking medium\nsummarize URL --model openai/gpt-5.4 --service-tier fast --thinking low\n```\n\nCompatibility aliases:\n\n- `--model gpt-fast` / `--model fast`: `openai/gpt-5.5` with fast service tier and medium thinking.\n- `--model openai/gpt-5.5-fast` or `--model openai/gpt-5.4-mini-fast`: strip the `-fast` suffix for the API model id and use fast service tier.\n- `--model codex-fast`: explicit Codex CLI fast preset.\n\n## Env\n\n- `OPENAI_API_KEY` (required for `openai/...` models)\n- `OPENAI_USE_CHAT_COMPLETIONS` (optional; force chat completions)\n\n## Flags\n\n- `--model openai/<model>`\n- `--fast`\n- `--service-tier default|fast|priority|flex`\n- `--thinking none|low|medium|high|xhigh|max`\n- `--length short|medium|long|xl|xxl|<chars>`\n  - This is _soft guidance_ to the model (no hard truncation).\n- `--max-output-tokens <count>`\n  - Hard cap for output tokens (optional).\n- `--json` (includes prompt + summary in one JSON object)\n\n## Config\n\n```json\n{\n  \"openai\": {\n    \"serviceTier\": \"fast\",\n    \"thinking\": \"medium\"\n  }\n}\n```\n\n`openai.reasoningEffort` is the long-form alias for `openai.thinking`. Model presets can also set `serviceTier`, `thinking` / `reasoningEffort`, and `textVerbosity`.\n\nUse `\"serviceTier\": \"fast\"` in summarize config and model presets. OpenAI API requests map that to `service_tier=\"priority\"`; `\"flex\"` and explicit `\"priority\"` pass through as-is. Use `--service-tier default` to clear a configured tier for one run.\n\n## PDF inputs\n\n- When a PDF is provided and `--preprocess auto` is used, summarize sends the PDF as a file input via the OpenAI Responses API.\n- Document streaming is disabled for file inputs; non-streaming calls are used instead.\n","packages/core/README.md":"# @steipete/summarize-core\n\nCore library for Summarize (content extraction + prompt builders).\n\n- CLI package: `@steipete/summarize`\n- Recommended imports (library use): `@steipete/summarize-core/content`, `@steipete/summarize-core/prompts`\n\nThe content entry point also exports DNS-pinned network helpers. `fetchWithDnsPinnedAddresses` accepts addresses attached with `attachDnsPinnedAddresses`; callers must validate those addresses first or use `createNetworkGuardedFetch` for validation. The transport honors cancellation from either a `Request` or its init options, returns null bodies for HEAD and HTTP 204/205/304, and rejects invalid HTTP responses through its promise.\n\nThe network guard revalidates every followed redirect and cancels discarded redirect bodies. Same-origin redirects retain request options and credentials; origin changes strip explicit authorization and cookie headers, including changes of scheme or port. Manual redirects remain available for the caller to consume.\n\nThe `@steipete/summarize-core/processes` entry point provides `signalTrackedProcess(child, signal)` for stopping one tracked command and its process tree, alongside `terminateTrackedProcesses(signal)` for all tracked commands. Use the per-command helper for deadlines so sibling work continues.\n"},"files":{".agents/skills/summarize/SKILL.md":"---\nname: summarize\ndescription: \"Summarize CLI: URLs, files, YouTube, transcripts, media, extraction, and JSON output.\"\n---\n\n# Summarize\n\nUse the `summarize` CLI as the canonical interface. Prefer a released binary on `PATH`; inside this repository, use `pnpm -s summarize` for the current checkout.\n\n## Start\n\n1. Confirm the command and current contract:\n\n   ```bash\n   summarize --version\n   summarize --help\n   ```\n\n2. Inspect model/provider readiness when a summary needs an LLM:\n\n   ```bash\n   summarize status\n   summarize status --json\n   ```\n\n3. Run the narrowest workflow below. Quote URLs and paths. Add `--timeout 2m` for slow remote or media inputs.\n\nNever print, request, or copy API-key values. `summarize status` reports availability without exposing secrets.\n\n## Summarize\n\nWeb page or remote document:\n\n```bash\nsummarize \"https://example.com/article\"\nsummarize \"https://example.com/report.pdf\" --length short\n```\n\nLocal file or stdin:\n\n```bash\nsummarize \"./report.pdf\"\nsummarize \"./recording.m4a\"\nprintf '%s\\n' \"Long text to summarize\" | summarize -\n```\n\nUse `--plain` for unrendered Markdown/text. Use `--language`, `--length`, `--prompt`, or `--prompt-file` only when the task requires an override. Use `--cli codex`, `--cli claude`, or another installed CLI provider when the user requests that provider or no direct API provider is configured.\n\n## Extract without a summary\n\nUse `--extract` to stop after extraction or transcription:\n\n```bash\nsummarize \"https://example.com/article\" --extract --format md\nsummarize \"./report.pdf\" --extract --format md\nsummarize \"https://youtu.be/VIDEO_ID\" --extract --format md\n```\n\n`--extract` does not support stdin. Extraction can still call configured transcription, OCR, Firecrawl, or Markdown services; it only skips the final summary call. `--markdown-mode llm` also invokes an LLM to reshape extracted text.\n\n## YouTube, audio, and video\n\nDefault transcript selection:\n\n```bash\nsummarize \"https://youtu.be/VIDEO_ID\"\nsummarize \"https://youtu.be/VIDEO_ID\" --extract --format md --timestamps\n```\n\nUse `--youtube web` to require web captions or `--youtube yt-dlp` to require the download/transcription path. Keep `auto` unless the user needs a specific source.\n\nLocal or remote audio/video:\n\n```bash\nsummarize \"./interview.mp3\" --extract\nsummarize \"./interview.mp4\" --extract --timestamps\nsummarize \"./interview.mp3\" --extract --diarize\n```\n\n`--transcriber auto` is the default. Use an explicit transcriber only when requested or diagnosing a provider. Diarization may require configured ElevenLabs or OpenAI access. Speaker identification is a separate opt-in step; do not infer identities without evidence.\n\nFor slides:\n\n```bash\nsummarize \"https://youtu.be/VIDEO_ID\" --slides\nsummarize \"./talk.mp4\" --slides --extract\n```\n\nSlide extraction may require `yt-dlp`; OCR requires `tesseract`.\n\n## JSON for automation\n\nUse JSON when another command or agent will parse the result:\n\n```bash\nsummarize \"https://example.com\" --json --metrics off > result.json\njq -r '.summary // .extracted.content // empty' result.json\n```\n\nThe stable top-level envelope contains `input`, `env`, `extracted`, `prompt`, `llm`, `metrics`, and `summary`. `summary` or `llm` can be `null` when extraction or a no-model path handles the input. In `--extract --json` mode, read extracted text from `.extracted.content`.\n\nJSON stays on stdout. Progress, warnings, and finish metrics stay on stderr. Do not merge stderr into stdout before parsing. Use `--metrics detailed` only when the task needs usage details.\n\n## Configuration and dependencies\n\nPrecedence: CLI flags, process environment, `~/.summarize/config.json`, built-in defaults. Prefer flags for one run; change config only when the user asks for a persistent default.\n\nUseful diagnostics:\n\n```bash\nsummarize status --verbose\nsummarize status --probe\nsummarize \"INPUT\" --verbose\n```\n\nPlain web summaries need no media tools. Media paths may use `ffmpeg`, `yt-dlp`, local Whisper/ONNX, or configured cloud transcription. Website fallback may use Firecrawl. Confirm the exact missing capability from the error before installing tools or changing config.\n\nInputs may be sent to the selected model, extraction, OCR, or transcription provider. For confidential material, confirm the approved provider or use an approved local path before running the command.\n\n## Verify\n\nAfter every run:\n\n- Require exit status `0`.\n- Require non-empty summary or extracted content.\n- For JSON, parse stdout with `jq` or another JSON parser.\n- For source-sensitive work, inspect `extracted`, `llm`, and stderr diagnostics rather than assuming the selected path.\n- Re-run the exact final command after changing provider, config, or flags.\n\nFor current option details, run `summarize --help` and read the repository documentation:\n\n- [Quickstart](../../../docs/quickstart.md)\n- [Main command](../../../docs/commands/summarize.md)\n- [Configuration](../../../docs/config.md)\n- [YouTube](../../../docs/youtube.md)\n- [Media](../../../docs/media.md)\n- [Extraction](../../../docs/extract-only.md)\n\n## Ownership\n\nThis file is the canonical agent workflow for the Summarize product. Keep generic agent workflows in `openclaw/agent-skills`; keep Summarize CLI behavior here. Downstream integrations should link to this file at a released tag or pinned commit and retain only their packaging or integration-specific notes. Do not maintain a second broad command guide downstream.\n",".agents/skills/summarize/agents/openai.yaml":"interface:\n  display_name: \"Summarize\"\n  short_description: \"Summarize URLs, files, and media with the CLI\"\n  default_prompt: \"Use $summarize to extract or summarize this URL, file, or media input.\"\n","AGENTS.md":"# Summarize Guardrails\n\n- Hard rule: single source of truth = `~/Projects/summarize`; never commit in `vendor/summarize` (treat it as a read-only checkout).\n- Note: multiple agents often work in this folder. If you see files/changes you do not recognize, ignore them and list them at the end.\n\n## Workspace layout (note)\n\n- Monorepo (pnpm workspace).\n- Packages:\n  - `@steipete/summarize` = CLI + UX (TTY/progress/streaming). Depends on core.\n  - `@steipete/summarize-core` (`packages/core`) = library surface for programmatic use (Sweetistics etc). No CLI entrypoints.\n- Versioning: lockstep versions; publish order: core first, then CLI (`scripts/release.sh` / `RELEASING.md`).\n- Homebrew/core formula is not owned here; BrewTestBot autobumps releases about every 3h. Do not block or manually manage it; ship and continue.\n- Chrome Web Store: every release must upload the matching `dist-chrome/summarize-chrome-extension-v<version>.zip` to item `cejgnmmhbbpdmjnfppjdfkocebngehfg`, submit it for review with automatic publishing, and verify the exact pending/published version. Skip only when every shipped change is daemon-side and the packaged extension/companion contract is unchanged.\n- Dev:\n  - Build: `pnpm run build` (builds core first; also runs during install via `prepare`)\n  - Gate: `pnpm run check`\n  - Import from apps: prefer `@steipete/summarize-core` to avoid pulling CLI-only deps.\n- Dependencies: stable releases need a 7-day stabilization delay before adoption; prereleases remain excluded unless already adopted.\n- Daemon: restart with `pnpm summarize daemon restart`; verify via `pnpm summarize daemon status`.\n- Rebuild (extension + daemon): run **both** in order:\n  1. `pnpm -C apps/chrome-extension build`\n  2. `pnpm summarize daemon restart`\n- Extension tests:\n  - `pnpm -C apps/chrome-extension test:chrome` = supported automated path.\n  - Firefox Playwright extension tests are not reliable (`moz-extension://` limitation); default `test:firefox` runs a temporary-install smoke test.\n  - Use `pnpm -C apps/chrome-extension test:firefox:force` only for explicit diagnostics.\n- Commits: use `committer \"type: message\" <files...>` (Conventional Commits).\n","docs/commands/daemon.md":"---\ntitle: summarize daemon\npermalink: /docs/commands/daemon.html\nkicker: command\nsummary: \"Manage the local daemon and Chrome Native Messaging bridge used by the Side Panel.\"\n---\n\n# `summarize daemon`\n\n```text\nsummarize daemon <subcommand> [options]\n```\n\nManages the local HTTP daemon and its browser integration. The daemon binds to `127.0.0.1` only and requires a shared bearer token. Chrome reaches it through an optional exact-ID Native Messaging host; Firefox retains its existing loopback integration. The daemon autostarts via the right service manager for your platform.\n\n| Platform | Service               |\n| -------- | --------------------- |\n| macOS    | LaunchAgent (launchd) |\n| Linux    | systemd user service  |\n| Windows  | Scheduled Task        |\n\nIf you only use the CLI, you don't need any of this.\n\n## Subcommands\n\n### `install`\n\nInstall or upgrade the autostart service, write `~/.summarize/daemon.json`, and register Chrome native host `com.steipete.summarize` on macOS/Linux.\n\n```bash\nsummarize daemon install --token <TOKEN>\nsummarize daemon install --token <TOKEN> --port 8787\nsummarize daemon install --token <TOKEN> --dev --extension-id <UNPACKED_ID>\n```\n\n`--token <token>` is **required** on first install; the extension prints one after pairing. Re-running `install` with a new token adds another paired browser instead of invalidating the old one. The native host manifest allows only Chrome Web Store extension ID `cejgnmmhbbpdmjnfppjdfkocebngehfg`.\n\n### `restart`\n\nRestart the autostart service. Useful after upgrading summarize or editing `daemon.json`.\n\n```bash\nsummarize daemon restart\n```\n\n### `status`\n\nProbe the autostart service, Chrome native-host registration, and the running daemon's health endpoint.\n\n```bash\nsummarize daemon status\n```\n\n### `uninstall`\n\nUnload the autostart service and remove the user-level Chrome native host. On macOS the daemon plist is moved to Trash so you can undo.\n\n```bash\nsummarize daemon uninstall\n```\n\n### `run`\n\nRun the daemon in the foreground. The autostart entry uses this internally; use it directly inside containers, on systems without launchd/systemd, or while debugging.\n\n```bash\nsummarize daemon run --port 8787\n```\n\n## Options\n\n`--port <n>`\n: TCP port. Default `8787`. For a non-default port, set the same value in the extension under **Options → Runtime → Daemon → Port**. The native host reads `daemon.json` and rejects mismatched requests.\n\n`--token <token>`\n: Bearer token. Required for `install`; also accepted by `run`, which adds it alongside the stored tokens for that run (required when no `daemon.json` exists). Stored in `~/.summarize/daemon.json` (mode `0600`).\n\n`--dev`\n: Install a service that runs `src/cli.ts` via Node's native TypeScript support from the current repo. Useful while hacking on the daemon — don't ship it to users.\n\n`--extension-id <id>`\n: With `--dev`, bind the native host to an unpacked Chrome extension ID. Production installs always use the exact Web Store ID.\n\n## HTTP endpoints\n\nThe daemon is documented in detail in [Chrome extension](../chrome-extension.md) and [Agent / daemon](../agent.md). At a glance:\n\n- `POST /v1/summarize` — start a run. Bearer-auth required. Returns `{ ok, id }` JSON (`coalesced: true` when it joins an in-flight run for the same request).\n- `GET /v1/summarize/{id}/events` — SSE stream of progress events and the final result for a run.\n- `GET /health` — health probe (used by `status`).\n\n## Files\n\n`~/.summarize/daemon.json`\n: Bearer token(s), port, and an env snapshot captured at install (includes provider API keys). Mode `0600`.\n\n`~/.summarize/daemon.log`\n: Rolling log written by the autostart service.\n\n## Notes\n\n- **Containers** — `install` starts the daemon for the current container session but does not register a Scheduled Task / unit. Run `summarize daemon run` from your entrypoint. Do not expose the port as a Chrome Native Messaging substitute.\n- **Token rotation** — running `install --token <NEW>` adds a new paired browser; old browsers keep working. Edit `daemon.json` by hand to revoke.\n- **Multiple installs** — only one daemon per user. Reinstall to upgrade; omitting `--port` preserves the configured port.\n- **Windows** — the npm-installed CLI still needs a packaged native-host `.exe`; do not route daemon traffic through the Direct-provider loopback grants as a workaround. Direct and Browser modes continue to work.\n\n## See also\n\n- [Chrome extension](../chrome-extension.md) — pairing flow + Side Panel UI.\n- [Agent / daemon](../agent.md) — automation surface.\n","docs/commands/index.md":"---\ntitle: Commands\npermalink: /docs/commands/\nkicker: reference\nsummary: \"Every summarize subcommand and flag, with examples.\"\n---\n\n# Command reference\n\n`summarize` is one binary with a handful of subcommands. The default subcommand is `summarize` itself — the one you use 99% of the time. The others wrap related tooling.\n\n## Subcommands\n\n- [`summarize`](summarize.md) — main command. Takes a URL, file, or stdin and produces a summary or extracted content.\n- [`summarize status`](../cli.md#cli-discovery) — print the selected model, enabled providers, and runtime status.\n- [`summarize slides`](slides.md) — extract scene-change keyframes from a YouTube URL, direct video URL, or local video file into PNGs (and optional OCR text). Standalone version of the `--slides` flag.\n- [`summarize transcriber`](transcriber.md) — set up local ONNX transcription (Parakeet, Canary). Prints the env vars you need.\n- [`summarize daemon`](daemon.md) — manage the local HTTP daemon that the Chrome Side Panel talks to. Subcommands: `install`, `restart`, `status`, `uninstall`, `run`.\n- [`summarize refresh-free`](refresh-free.md) — scan OpenRouter `:free` models, write working candidates to `~/.summarize/config.json`.\n- `summarize help [topic]` — print help for the CLI or a subcommand (`slides`, `status`, `daemon`, `transcriber`, `refresh-free`).\n\n## Output discipline\n\nAll subcommands keep the same output discipline — straight from gogcli's playbook so pipes and scripts stay parseable:\n\n- **stdout:** the result. Plain text, Markdown, JSON, or files (slides only).\n- **stderr:** progress, prompts, warnings, and errors.\n- `--json` produces a stable envelope on stdout.\n- `--no-color` strips ANSI; `--plain` skips ANSI/OSC rendering for Markdown.\n\n## Global behavior\n\nOnly two flags apply to every subcommand; the rest are per-command:\n\n| Flag                          | Where it works                                                                                                                             |\n| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |\n| `--locale <locale>`           | Everywhere. Interface language: `auto` plus the shipped UI locales (`SUMMARIZE_LOCALE` too).                                               |\n| `--help`                      | Everywhere (`summarize help <topic>` prints topic help).                                                                                   |\n| `-V`, `--version`             | `summarize`, `summarize slides`.                                                                                                           |\n| `--json`                      | `summarize`, `summarize slides`, `summarize status`.                                                                                       |\n| `--no-color`                  | `summarize`, `summarize status`, `summarize refresh-free`, `summarize transcriber`.                                                        |\n| `--theme <name>`              | `summarize`, `summarize slides`, `summarize transcriber` (`SUMMARIZE_THEME` env var also works).                                           |\n| `--verbose` / `--debug`       | `summarize`, `summarize slides`, `summarize refresh-free`, `summarize daemon`, `summarize transcriber`. `status` accepts `--verbose` only. |\n| `--metrics off\\|on\\|detailed` | `summarize` only.                                                                                                                          |\n| `--timeout <duration>`        | `summarize`, `summarize slides`.                                                                                                           |\n\n## Exit codes\n\n| Code  | Meaning                                                                     |\n| ----- | --------------------------------------------------------------------------- |\n| `0`   | Success.                                                                    |\n| `1`   | Any failure — usage errors, extraction, model, network, and timeouts alike. |\n| `130` | Interrupted by SIGINT (Ctrl+C).                                             |\n| `143` | Terminated by SIGTERM.                                                      |\n\n`summarize daemon` and `summarize transcriber` still exit `1` when the underlying service install (launchd, systemd, schtasks) fails; the platform's own error text is included in the message — check `--verbose` output for the raw error.\n","docs/commands/refresh-free.md":"---\ntitle: summarize refresh-free\npermalink: /docs/commands/refresh-free.html\nkicker: command\nsummary: \"Scan OpenRouter :free models and write working candidates to config.\"\n---\n\n# `summarize refresh-free`\n\n```text\nsummarize refresh-free [--runs 2] [--smart 3] [--min-params 27b]\n                       [--max-age-days 180] [--set-default] [--verbose]\n```\n\nProbes [OpenRouter](https://openrouter.ai)'s catalog for `:free` models, runs them on a small benchmark, and writes the working ones to `models.free` in `~/.summarize/config.json`. Useful when you want to use `--model free` without picking a specific OpenRouter slug.\n\nNeeds `OPENROUTER_API_KEY` in the environment.\n\n## What it does\n\n1. Pulls the OpenRouter model catalog.\n2. Filters to models tagged `:free` that meet `--min-params` and `--max-age-days`.\n3. Benchmarks every candidate once against a sanity prompt, then probes the shortlisted candidates `--runs` more times; ranks by `--smart` heuristics (latency, completion length, refusal rate).\n4. Writes the survivors to `models.free` in `~/.summarize/config.json`.\n5. With `--set-default`, also sets top-level `model` to `free`.\n\nAfter the run, `summarize \"https://example.com\" --model free` rotates through the saved list until one succeeds.\n\n## Flags\n\n`--runs <n>`\n: Extra refinement probes per shortlisted candidate after the initial benchmark run (`1 + --runs` total). `0` skips refinement. Default `2`.\n\n`--smart <n>`\n: How many top candidates to keep. Default `3`.\n\n`--min-params <size>`\n: Minimum parameter count. Accepts `7b`, `27b`, `70b`, etc. Default `27b`.\n\n`--max-age-days <n>`\n: Reject models older than N days based on OpenRouter's metadata. Default `180`.\n\n`--set-default`\n: Also set `model: \"free\"` at the top level of `~/.summarize/config.json`.\n\n`--verbose` / `--debug`\n: Per-candidate progress, timings, and rejection reasons on stderr.\n\n## Examples\n\n```bash\n# Quick refresh; keep the best 3 free models ≥27B, ≤180d old.\nsummarize refresh-free\n\n# Looser filter — accept smaller / older models.\nsummarize refresh-free --min-params 7b --max-age-days 365\n\n# Refresh and also set the default model.\nsummarize refresh-free --set-default\n\n# Verbose ranking output for debugging.\nsummarize refresh-free --runs 3 --smart 5 --verbose\n```\n\n## Output\n\n`~/.summarize/config.json` is updated in place. The relevant section ends up looking like:\n\n```json\n{\n  \"models\": {\n    \"free\": [\"openai/gpt-oss-120b:free\", \"z-ai/glm-4.6:free\", \"deepseek/deepseek-r1:free\"]\n  }\n}\n```\n\nA short summary of survivors and rejected candidates is printed on stderr. The only stdout line is the localized config-write confirmation, e.g. `Wrote /Users/you/.summarize/config.json (models.free)` — a sentence containing the path, not a bare path value.\n\nColor follows the rest of the CLI: `FORCE_COLOR=0` disables it, while a nonzero `FORCE_COLOR` takes precedence over `NO_COLOR`. Without an override, color requires a capable terminal.\n\n## See also\n\n- [LLM overview](../llm.md) — `--model` syntax, including `free`.\n- [Auto selection](../model-auto.md) — how `auto` picks across providers.\n- [Config](../config.md) — full schema for `~/.summarize/config.json`.\n","docs/commands/slides.md":"---\ntitle: summarize slides\npermalink: /docs/commands/slides.html\nkicker: command\nsummary: \"Extract scene-change keyframes from a video source into PNG files.\"\n---\n\n# `summarize slides`\n\n```text\nsummarize slides <source> [flags]\n```\n\nExtracts slide-shaped keyframes from a YouTube URL, direct video URL, or local video file using FFmpeg scene detection. Native ffmpeg is preferred; bundled FFmpeg WebAssembly is used when native `ffmpeg`/`ffprobe` are unavailable. Output is a directory of PNGs (and optional OCR text). This is the standalone form of the `--slides` flag on the main command — useful when you only want the slides without a summary.\n\n## Synopsis\n\n```bash\nsummarize slides \"https://youtu.be/...\"\nsummarize slides \"https://youtu.be/...\" --render auto\nsummarize slides \"https://youtu.be/...\" --slides-ocr -o ./out\nsummarize slides \"https://example.com/lecture.mp4\" --slides-max 12\nsummarize slides ./lecture.mp4 --slides-max 12\n```\n\n## Requirements\n\n- Bundled FFmpeg WebAssembly, or native `ffmpeg` on PATH for faster extraction and broader codec support.\n- `yt-dlp` on PATH for YouTube URLs.\n- `tesseract` on PATH for `--slides-ocr`.\n\nIf a required tool is missing, summarize prints a clear warning and exits non-zero.\n\n## Flags\n\n`--slides-ocr`\n: Run OCR on every extracted slide. Stores `ocrText` and `ocrConfidence` in `slides.json` and the JSON response.\n\n`--slides-dir <dir>`\n: Output base directory. Default: `./slides`. A per-video subfolder is created inside.\n\n`-o, --output <dir>`\n: Alias for `--slides-dir`.\n\n`--slides-scene-threshold <value>`\n: Scene detection threshold, `0.1`–`1.0`. Default `0.3`. Lower values detect more scenes (more slides); higher values are stricter.\n\n`--slides-max <count>`\n: Cap on extracted slides. Default `6`.\n\n`--slides-min-duration <seconds>`\n: Minimum gap between slides. Default `2`.\n\n`--render <mode>`\n: Inline render of thumbnails: `auto`, `kitty`, `iterm`, `none`. Default `none` — paths are printed instead.\n\n`--theme <name>`\n: Pick a CLI theme.\n\n`--timeout <duration>`\n: Per-operation timeout setting. Default `2m`; not an overall wall-clock deadline. yt-dlp downloads and FFmpeg scene detection allow at least `5m`, and individual extraction/probe steps have their own limits.\n\n`--no-cache`\n: Force re-download and re-extraction (bypasses both caches).\n\n`--json`\n: JSON envelope on stdout. Disables inline rendering.\n\n`--verbose` / `--debug`\n: Detailed progress on stderr.\n\n`-V`, `--version`\n: Print version and exit.\n\n## Output\n\nEach run writes a directory like:\n\n```text\nslides/<source-id>/\n  slide_0001_18.60s.png\n  slide_0002_42.20s.png\n  ...\n  slides.json\n```\n\nThe filenames include the slide index and timestamp. `slides.json` records the manifest, including OCR results when requested; OCR does not create separate text files. `ocrConfidence` uses a 0–1 scale.\n\nIn `--json` mode, stdout contains an envelope like this (additional extraction metadata omitted):\n\n```json\n{\n  \"ok\": true,\n  \"slides\": {\n    \"sourceUrl\": \"https://example.com/lecture.mp4\",\n    \"slidesDir\": \"/absolute/path/slides/<id>\",\n    \"slides\": [\n      {\n        \"index\": 1,\n        \"timestamp\": 18.6,\n        \"imagePath\": \"/absolute/path/slides/<id>/slide_0001_18.60s.png\",\n        \"ocrText\": \"Recognized slide text\",\n        \"ocrConfidence\": 0.92\n      }\n    ]\n  }\n}\n```\n\n## Inline rendering\n\n`--render auto` detects Kitty (`KITTY_WINDOW_ID`) and iTerm (`TERM_PROGRAM=iTerm.app`) and uses the matching image protocol. On unsupported terminals, slides are listed by path instead.\n\n## Examples\n\n```bash\n# Quick preview in iTerm/Kitty.\nsummarize slides \"https://youtu.be/...\" --render auto\n\n# Big lecture, more granular cuts.\nsummarize slides \"https://youtu.be/...\" \\\n  --slides-max 24 --slides-scene-threshold 0.2\n\n# Pipe-friendly JSON for an automation.\nsummarize slides \"https://youtu.be/...\" --json | jq '.slides.slides[].imagePath'\n\n# Force re-extraction after editing the source video.\nsummarize slides \"./talk.mp4\" --no-cache -o ./out\n```\n\n## See also\n\n- [Slides mode](../slides.md) — the inline `--slides` flag on the main command.\n- [Slides rendering flow](../slides-rendering-flow.md) — pipeline internals.\n","docs/commands/summarize.md":"---\ntitle: summarize\npermalink: /docs/commands/summarize.html\nkicker: command\nsummary: \"Main command. URL, file, or stdin → clean text → summary.\"\n---\n\n# `summarize`\n\n```text\nsummarize [input] [flags]\n```\n\nTakes a URL, local file path, or `-` for stdin and produces a summary. With `--extract`, prints cleaned content instead of summarizing; stdin is not supported in extract mode.\n\n## Synopsis\n\n```bash\nsummarize \"https://example.com/article\"\nsummarize ./report.pdf --model openai/gpt-5-mini\nsummarize \"https://youtu.be/...\" --slides --slides-ocr\npbpaste | summarize -\nsummarize \"https://example.com\" --extract --format md > clean.md\nsummarize \"https://example.com\" --json --metrics detailed\n```\n\n## Input\n\n- **URL** — http/https. YouTube, podcast hosts, generic articles, raw media.\n- **File path** — PDF, image, audio, video, plain text, Markdown, HTML.\n- **`-`** — read content from stdin (text or binary).\n\nIf `[input]` is omitted, summarize prints concise help and exits.\n\n## Flags\n\n### Extraction\n\n`--extract`\n: Print extracted content and exit. No LLM call. Supports URLs, YouTube/direct media, local audio/video, and local PDFs; `-` stdin is not supported. The `--extract-only` alias is hidden but still works.\n: Extraction can still use configured remote transcription, OCR, or Markdown providers for media/PDF inputs.\n\n`--format <format>`\n: `md`/`markdown` or `text`/`txt`/`plain`. Controls website extraction format and whether files are preprocessed to Markdown for model compatibility. Default: `text`. Default in `--extract` mode for URLs: `md`.\n\n`--firecrawl <mode>`\n: `off`, `auto`, `always`. `auto` falls back to Firecrawl when local extraction looks blocked or thin. Needs `FIRECRAWL_API_KEY`.\n\n`--preprocess <mode>`\n: `off`, `auto`, `always`. Default `auto`. Controls `markitdown` usage for files. `always` only affects file inputs.\n: Image-only PDFs can retry through OpenAI vision OCR when `OPENAI_API_KEY` is set. Set `MARKITDOWN_OCR_MODEL` to choose the OCR model, or `MARKITDOWN_OCR_DPI` to tune rendered page size.\n\n`--markdown-mode <mode>`\n: `off`, `auto`, `llm`, `readability`. For websites: HTML → Markdown strategy. For YouTube/transcripts: `llm` formats raw transcripts into clean Markdown with headings. The `--markdown` alias is hidden and deprecated.\n\n`--max-extract-characters <count>`\n: Cap printed characters in `--extract` mode. Default: unlimited.\n\n### YouTube / video\n\n`--youtube <mode>`\n: `auto`, `web`, `apify`, `yt-dlp`, `no-auto` (skip auto-generated captions). Default `auto`.\n\n`--transcriber <name>`\n: Select the local transcription stage: `auto`, `whisper`, `parakeet`, `canary`. Default `auto` — Groq still runs first when keyed, then local ONNX/`whisper.cpp`, then cloud fallbacks.\n\n`--video-mode <mode>`\n: `auto`, `transcript`, `understand`. `understand` prefers vision/video understanding when supported.\n\n`--embedded-video <mode>`\n: `auto`, `off`, `prefer`, `both`. Controls embedded YouTube handling on regular web pages: `off` keeps the article text only, `prefer` favors the video transcript, `both` combines labeled article + transcript sections. Default `auto` — uses only high-confidence primary embeds. See [Website mode](../website.md).\n\n`--timestamps`\n: Include timestamps in transcripts when available.\n\n`--diarize [provider]`\n: Add speaker labels to YouTube, local audio/video, or direct media URLs. Provider: `auto`, `elevenlabs`, or `openai`.\n\n`--identify-speakers` / `--no-identify-speakers`\n: Resolve generic diarization labels to names, or disable configured resolution for one run. Uses authoritative anchors and OpenAI GPT-5.5 context inference.\n\n`--speaker-profile <name>`\n: Select a reusable profile from `speakers.profiles` in the config file.\n\n`--speaker-at <timestamp=name>`\n: Name the speaker active at a timestamp. Repeat the flag for multiple speakers.\n\n`--remember-speakers`\n: Atomically persist resolved names, anchors, and a transcript-hash-guarded source mapping under the selected profile.\n\n### Slides\n\n`--slides [on|off]` / `--no-slides`\n: Extract slides from a YouTube URL, direct video URL, or local video file and render inline alongside the summary. Combine with `--extract` to interleave slides in the full transcript. See [Slides mode](../slides.md).\n: The optional value accepts boolean words (`on`/`off`, `true`/`false`, `yes`/`no`, `1`/`0`); anything else is rejected. Use `--no-slides` to disable slide extraction enabled in the config file for one run.\n\n`--slides-ocr` / `--no-slides-ocr`\n: Run OCR on extracted slides. Requires `tesseract`.\n: Use `--no-slides-ocr` to disable configured slide OCR while retaining slide extraction.\n\n`--slides-debug`\n: Print slide image paths instead of rendering inline (useful in non-image terminals).\n\n`--slides-dir <dir>`\n: Output directory base. Default `./slides`.\n\n`--slides-scene-threshold <value>`\n: Scene detection threshold, `0.1`–`1.0`. Default `0.3`.\n\n`--slides-max <count>`\n: Cap on extracted slides. Default `6`.\n\n`--slides-min-duration <seconds>`\n: Minimum gap between slides. Default `2`.\n\n### Summary control\n\n`--length <length>`\n: `short`, `medium`, `long`, `xl`, `xxl` (or `s`/`m`/`l`) or a character cap like `20000` or `20k`. Default `long`. Override globally via `output.length` in [Config](../config.md).\n\n`--force-summary`\n: Always run the LLM, even when extracted content is shorter than the requested length.\n\n`--language, --lang <language>`\n: `auto`, `en`, `de`, `english`, `german`, … Default `auto` (matches source). Configurable via `output.language`.\n\n`--locale <locale>`\n: CLI interface language: `auto` plus the shipped UI locales (`en`, `de`, `fr`, `es`, `it`, `pt-BR`, `nl`, `pl`, `ru`, `ja`, `zh-Hans`, `zh-Hant`, `ko`, `tr`). Default follows the system locale with English fallback. `SUMMARIZE_LOCALE` also works. See [Localization](../localization.md).\n\n`--prompt <text>` / `--prompt-file <path>`\n: Override the summary prompt. Content is appended after the override.\n\n### Models\n\n`--model <model>`\n: Model id. `auto`, `<config-preset>`, `cli/<provider>/<model>`, `xai/...`, `openai/...`, `nvidia/...`, `minimax/...`, `google/...`, `anthropic/...`, `zai/...`, `ollama/<model>` (local Ollama), `openclaw/<model>` (shorthand for `cli/openclaw/<model>`), or `openrouter/<author>/<slug>`. Default `auto`. See [LLM overview](../llm.md).\n\n`--cli [provider]`\n: Use a logged-in CLI provider: `claude`, `gemini`, `codex`, `agent`, `openclaw`, `opencode`, `copilot`, `agy`, `pi`, `devin`, `grok`. Equivalent to `--model cli/<provider>`. Without a value: enable CLI providers in auto-selection.\n\n`--thinking <effort>`\n: Reasoning effort. `none`, `low`, `medium`, `high`, `xhigh`, `max` (GPT-6 models). Aliases: `off`, `min`, `med`, `mid`, `x-high`, `extra-high`. Affects reasoning-capable models on the dispatched provider (OpenAI, Anthropic Claude 4+, pi CLI).\n\n`--service-tier <tier>`\n: OpenAI service tier. `default`, `fast`, `priority`, `flex`. Maps to `service_tier` on the request.\n\n`--fast`\n: Shortcut for OpenAI `service_tier=priority`. Same effect as `--service-tier fast`.\n\n`--max-output-tokens <count>`\n: Hard cap for LLM output tokens. Accepts `2000`, `2k`. Overrides provider defaults.\n\n`--retries <count>`\n: LLM retry attempts after timeouts or transient API failures. `0`–`5`. Default `1`.\n\n### Output\n\n`--json`\n: Structured JSON envelope on stdout. Includes prompt + metrics. Disables streaming.\n\n`--stream <mode>`\n: `auto`, `on`, `off`. Default `auto` (TTY-only). Disabled in `--json` mode.\n\n`--plain`\n: Keep raw text/Markdown — no ANSI/OSC rendering.\n\n`--no-color`\n: Disable ANSI colors.\n\n`--width <columns>`\n: Override terminal width for Markdown rendering. Default: auto-detect, max 120.\n\n`--theme <name>`\n: Pick a CLI theme. Run `summarize --help` for the list. Env: `SUMMARIZE_THEME`.\n\n### Cache\n\n`--no-cache`\n: Bypass the summary (LLM) cache. Media + transcript caches stay enabled.\n\n`--no-media-cache`\n: Disable the media download cache (`yt-dlp` outputs).\n\n`--cache-stats`\n: Print cache stats and exit.\n\n`--clear-cache`\n: Delete the cache database and exit.\n\nSee [Cache internals](../cache.md) for what's cached and where.\n\n### Diagnostics\n\n`--verbose`\n: Detailed progress on stderr.\n\n`--debug`\n: Alias for `--verbose`. Also defaults `--metrics` to `detailed`.\n\n`--metrics <mode>`\n: `off`, `on`, `detailed`. Default `on`. Adds a compact second-line breakdown on stderr when `detailed`.\n\n`--timeout <duration>`\n: Per-operation timeout for content fetching and LLM requests (not an overall wall-clock deadline). `30`, `30s`, `2m`, `5000ms`. Default `2m`.\n\n`-V`, `--version`\n: Print version and exit.\n\n## Examples\n\n```bash\n# Extracted plain text from a URL.\nsummarize \"https://example.com\" --extract\n\n# Extracted Markdown — prefers Firecrawl when configured.\nsummarize \"https://example.com\" --extract --format md\n\n# YouTube transcript as cleanly-formatted Markdown.\nsummarize \"https://www.youtube.com/watch?v=...\" \\\n  --extract --format md --markdown-mode llm\n\n# ElevenLabs diarization with verified speaker names.\nsummarize \"https://www.youtube.com/watch?v=...\" --extract \\\n  --diarize elevenlabs --identify-speakers \\\n  --speaker-profile my-podcast --speaker-at \"0:12=Host Name\" --remember-speakers\n\n# Inline slides + summary.\nsummarize \"https://www.youtube.com/watch?v=...\" --slides\n\n# Full transcript + inline slides.\nsummarize \"https://www.youtube.com/watch?v=...\" --slides --extract\n\n# Hard caps + a specific model.\nsummarize \"https://example.com\" \\\n  --length 20k --max-output-tokens 2k --timeout 2m \\\n  --model openai/gpt-5-mini\n\n# OpenAI fast tier with reasoning.\nsummarize \"https://example.com\" \\\n  --model openai/gpt-5.5 --fast --thinking medium\n\n# Config preset (alias defined in ~/.summarize/config.json).\nsummarize \"https://example.com\" --model mymodel\n\n# Strict JSON for scripts.\nsummarize \"https://example.com\" --json --verbose\n\n# Summarize the clipboard.\npbpaste | summarize -\n```\n\n## Environment\n\nThe provider keys and binary paths picked up at runtime are listed in [LLM overview](../llm.md#env). `SUMMARIZE_MODEL` overrides the default model selection; `SUMMARIZE_THEME` picks the theme; `SUMMARIZE_LOCALE` picks the interface language.\n\n## See also\n\n- [LLM overview](../llm.md) — how `--model` resolves to a provider.\n- [Website mode](../website.md), [YouTube](../youtube.md), [Media + podcasts](../media.md).\n- [Cache](../cache.md), [Firecrawl](../firecrawl.md).\n- [Config](../config.md) for persistent defaults.\n","docs/commands/transcriber.md":"---\ntitle: summarize transcriber\npermalink: /docs/commands/transcriber.html\nkicker: command\nsummary: \"Set up local ONNX transcription (Parakeet, Canary).\"\n---\n\n# `summarize transcriber`\n\n```text\nsummarize transcriber setup [--model parakeet|canary] [--theme <name>]\n```\n\nConfigures local ONNX transcription. The command **prints the env vars** you need to export — it doesn't write to your shell config. Once those vars are exported, `--transcriber auto` (or `SUMMARIZE_TRANSCRIBER=auto`) uses ONNX after Groq and before `whisper.cpp` and the remaining cloud fallbacks.\n\n## How auto picks a transcriber\n\nWhen `--transcriber auto` is set (default), summarize tries providers in this order:\n\n1. **Groq** — fastest cloud option. Needs `GROQ_API_KEY`.\n2. **Local ONNX** (Parakeet or Canary), then `whisper.cpp` — fully offline. ONNX needs the env vars from this command.\n3. **AssemblyAI / Gemini / OpenAI / FAL / Deepgram** — cloud fallbacks, in that order, gated by their respective API keys.\n\n`OPENAI_WHISPER_BASE_URL` changes the endpoint used by the OpenAI transcription stage; it is not a separate provider in the order above.\n\n## Subcommand\n\n### `summarize transcriber setup`\n\n`--model <name>`\n: `parakeet` (default) or `canary`. Picks which ONNX model the printed snippet targets.\n\n`--theme <name>`\n: CLI theme override.\n\nThe output is a labelled, copy-pasteable block of `export` lines for your shell. Re-run with the other model to switch.\n\n## Environment\n\nSet by the printed snippet:\n\n`SUMMARIZE_ONNX_PARAKEET_CMD`\n: Command to run Parakeet ONNX transcription. Use `{input}` as the audio-file placeholder.\n\n`SUMMARIZE_ONNX_CANARY_CMD`\n: Command to run Canary ONNX transcription. Use `{input}` as the audio-file placeholder.\n\n`SUMMARIZE_TRANSCRIBER`\n: Optional. Select the local stage with `auto`, `whisper`, `parakeet`, or `canary` without passing `--transcriber` every time.\n\n## Examples\n\n```bash\n# Default: Parakeet.\nsummarize transcriber setup\n\n# Set up Canary instead.\nsummarize transcriber setup --model canary\n\n# After exporting the printed vars:\nsummarize \"https://podcasts.apple.com/.../episode-...\" --transcriber parakeet\n```\n\n## See also\n\n- [ONNX transcription](../nvidia-onnx-transcription.md) — how to actually install the model + runtime.\n- [Transcript provider flow](../transcript-provider-flow.md) — full selection waterfall.\n","docs/openai.md":"---\ntitle: \"OpenAI\"\nkicker: \"models\"\nsummary: \"OpenAI model usage and flags.\"\nread_when:\n  - \"When changing OpenAI integration.\"\n---\n\n# OpenAI models\n\nUse OpenAI directly by choosing an `openai/...` model id.\n\nFor the full model/provider matrix, see `docs/llm.md`.\n\n## GPT-6\n\nUse the documented model ids: `openai/gpt-6-astra`, `openai/gpt-6-sol`, `openai/gpt-6-luna`, or `openai/gpt-6.1-sol`.\nSummarize uses the Responses API by default for direct OpenAI text and image requests, including streaming, and for PDF inputs. `OPENAI_USE_CHAT_COMPLETIONS=1` still selects Chat Completions for text and images.\nReasoning requests omit `temperature`, which GPT-6 rejects. GPT-6 Sol and Luna preserve temperature when explicitly using `--thinking none`; Astra and GPT-6.1 Sol require reasoning.\n\n```sh\nsummarize https://summarize.sh/ --model openai/gpt-6-astra --thinking medium --fast\nsummarize https://summarize.sh/ --model openai/gpt-6-sol --thinking medium\nsummarize https://summarize.sh/ --model openai/gpt-6-luna --thinking low\nsummarize https://summarize.sh/ --model openai/gpt-6.1-sol --thinking max\n```\n\nThese explicit model ids do not change the default model or existing presets.\nThe model picker and built-in pricing catalog include all four models. Standard input/output\nprices per million tokens are $10/$50 for Astra, $2/$10 for Sol and GPT-6.1 Sol, and $0.10/$0.50 for Luna.\nCost estimates use these standard rates; they do not include cache discounts, cache writes,\nfast/flex service tiers, or long-context premiums. See [OpenAI pricing](https://developers.openai.com/api/docs/pricing).\nAll four GPT-6 models support `low`, `medium`, `high`, `xhigh`, and `max`. Summarize accepts `max` only for these documented model ids.\nAn unsupported `--thinking none` request for Astra or GPT-6.1 Sol fails locally before sending an API request.\nSee OpenAI's [GPT-6 guide](https://developers.openai.com/api/docs/guides/latest-model) and model pages for [Astra](https://developers.openai.com/api/docs/models/gpt-6-astra), [Sol](https://developers.openai.com/api/docs/models/gpt-6-sol), [Luna](https://developers.openai.com/api/docs/models/gpt-6-luna), and [GPT-6.1 Sol](https://developers.openai.com/api/docs/models/gpt-6.1-sol).\n\n## Fast mode\n\nFast mode is a service tier, not a model id. Prefer flags:\n\n```sh\nsummarize URL --model openai/gpt-5.5 --fast --thinking medium\nsummarize URL --model openai/gpt-5.4 --service-tier fast --thinking low\n```\n\nCompatibility aliases:\n\n- `--model gpt-fast` / `--model fast`: `openai/gpt-5.5` with fast service tier and medium thinking.\n- `--model openai/gpt-5.5-fast` or `--model openai/gpt-5.4-mini-fast`: strip the `-fast` suffix for the API model id and use fast service tier.\n- `--model codex-fast`: explicit Codex CLI fast preset.\n\n## Env\n\n- `OPENAI_API_KEY` (required for `openai/...` models)\n- `OPENAI_USE_CHAT_COMPLETIONS` (optional; force chat completions)\n\n## Flags\n\n- `--model openai/<model>`\n- `--fast`\n- `--service-tier default|fast|priority|flex`\n- `--thinking none|low|medium|high|xhigh|max`\n- `--length short|medium|long|xl|xxl|<chars>`\n  - This is _soft guidance_ to the model (no hard truncation).\n- `--max-output-tokens <count>`\n  - Hard cap for output tokens (optional).\n- `--json` (includes prompt + summary in one JSON object)\n\n## Config\n\n```json\n{\n  \"openai\": {\n    \"serviceTier\": \"fast\",\n    \"thinking\": \"medium\"\n  }\n}\n```\n\n`openai.reasoningEffort` is the long-form alias for `openai.thinking`. Model presets can also set `serviceTier`, `thinking` / `reasoningEffort`, and `textVerbosity`.\n\nUse `\"serviceTier\": \"fast\"` in summarize config and model presets. OpenAI API requests map that to `service_tier=\"priority\"`; `\"flex\"` and explicit `\"priority\"` pass through as-is. Use `--service-tier default` to clear a configured tier for one run.\n\n## PDF inputs\n\n- When a PDF is provided and `--preprocess auto` is used, summarize sends the PDF as a file input via the OpenAI Responses API.\n- Document streaming is disabled for file inputs; non-streaming calls are used instead.\n","packages/core/README.md":"# @steipete/summarize-core\n\nCore library for Summarize (content extraction + prompt builders).\n\n- CLI package: `@steipete/summarize`\n- Recommended imports (library use): `@steipete/summarize-core/content`, `@steipete/summarize-core/prompts`\n\nThe content entry point also exports DNS-pinned network helpers. `fetchWithDnsPinnedAddresses` accepts addresses attached with `attachDnsPinnedAddresses`; callers must validate those addresses first or use `createNetworkGuardedFetch` for validation. The transport honors cancellation from either a `Request` or its init options, returns null bodies for HEAD and HTTP 204/205/304, and rejects invalid HTTP responses through its promise.\n\nThe network guard revalidates every followed redirect and cancels discarded redirect bodies. Same-origin redirects retain request options and credentials; origin changes strip explicit authorization and cookie headers, including changes of scheme or port. Manual redirects remain available for the caller to consume.\n\nThe `@steipete/summarize-core/processes` entry point provides `signalTrackedProcess(child, signal)` for stopping one tracked command and its process tree, alongside `terminateTrackedProcesses(signal)` for all tracked commands. Use the per-command helper for deadlines so sibling work continues.\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/steipete/summarize/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# Summarize Guardrails\n\n- Hard rule: single source of truth = `~/Projects/summarize`; never commit in `vendor/summarize` (treat it as a read-only checkout).\n- Note: multiple agents often work in this folder. If you see files/changes you do not recognize, ignore them and list them at the end.\n\n## Workspace layout (note)\n\n- Monorepo (pnpm workspace).\n- Packages:\n  - `@steipete/summarize` = CLI + UX (TTY/progress/streaming). Depends on core.\n  - `@steipete/summarize-core` (`packages/core`) = library surface for programmatic use (Sweetistics etc). No CLI entrypoints.\n- Versioning: lockstep versions; publish order: core first, then CLI (`scripts/release.sh` / `RELEASING.md`).\n- Homebrew/core formula is not owned here; BrewTestBot autobumps releases about every 3h. Do not block or manually manage it; ship and continue.\n- Chrome Web Store: every release must upload the matching `dist-chrome/summarize-chrome-extension-v<version>.zip` to item `cejgnmmhbbpdmjnfppjdfkocebngehfg`, submit it for review with automatic publishing, and verify the exact pending/published version. Skip only when every shipped change is daemon-side and the packaged extension/companion contract is unchanged.\n- Dev:\n  - Build: `pnpm run build` (builds core first; also runs during install via `prepare`)\n  - Gate: `pnpm run check`\n  - Import from apps: prefer `@steipete/summarize-core` to avoid pulling CLI-only deps.\n- Dependencies: stable releases need a 7-day stabilization delay before adoption; prereleases remain excluded unless already adopted.\n- Daemon: restart with `pnpm summarize daemon restart`; verify via `pnpm summarize daemon status`.\n- Rebuild (extension + daemon): run **both** in order:\n  1. `pnpm -C apps/chrome-extension build`\n  2. `pnpm summarize daemon restart`\n- Extension tests:\n  - `pnpm -C apps/chrome-extension test:chrome` = supported automated path.\n  - Firefox Playwright extension tests are not reliable (`moz-extension://` limitation); default `test:firefox` runs a temporary-install smoke test.\n  - Use `pnpm -C apps/chrome-extension test:firefox:force` only for explicit diagnostics.\n- Commits: use `committer \"type: message\" <files...>` (Conventional Commits).\n","isInternal":false,"tokens":550,"sizeBytes":2181},{"name":"openai.md","path":"docs/openai.md","rawUrl":"https://raw.githubusercontent.com/steipete/summarize/HEAD/docs/openai.md","title":"docs - OpenAI Codex & System Instructions","category":"root-instruction","format":"markdown","content":"---\ntitle: \"OpenAI\"\nkicker: \"models\"\nsummary: \"OpenAI model usage and flags.\"\nread_when:\n  - \"When changing OpenAI integration.\"\n---\n\n# OpenAI models\n\nUse OpenAI directly by choosing an `openai/...` model id.\n\nFor the full model/provider matrix, see `docs/llm.md`.\n\n## GPT-6\n\nUse the documented model ids: `openai/gpt-6-astra`, `openai/gpt-6-sol`, `openai/gpt-6-luna`, or `openai/gpt-6.1-sol`.\nSummarize uses the Responses API by default for direct OpenAI text and image requests, including streaming, and for PDF inputs. `OPENAI_USE_CHAT_COMPLETIONS=1` still selects Chat Completions for text and images.\nReasoning requests omit `temperature`, which GPT-6 rejects. GPT-6 Sol and Luna preserve temperature when explicitly using `--thinking none`; Astra and GPT-6.1 Sol require reasoning.\n\n```sh\nsummarize https://summarize.sh/ --model openai/gpt-6-astra --thinking medium --fast\nsummarize https://summarize.sh/ --model openai/gpt-6-sol --thinking medium\nsummarize https://summarize.sh/ --model openai/gpt-6-luna --thinking low\nsummarize https://summarize.sh/ --model openai/gpt-6.1-sol --thinking max\n```\n\nThese explicit model ids do not change the default model or existing presets.\nThe model picker and built-in pricing catalog include all four models. Standard input/output\nprices per million tokens are $10/$50 for Astra, $2/$10 for Sol and GPT-6.1 Sol, and $0.10/$0.50 for Luna.\nCost estimates use these standard rates; they do not include cache discounts, cache writes,\nfast/flex service tiers, or long-context premiums. See [OpenAI pricing](https://developers.openai.com/api/docs/pricing).\nAll four GPT-6 models support `low`, `medium`, `high`, `xhigh`, and `max`. Summarize accepts `max` only for these documented model ids.\nAn unsupported `--thinking none` request for Astra or GPT-6.1 Sol fails locally before sending an API request.\nSee OpenAI's [GPT-6 guide](https://developers.openai.com/api/docs/guides/latest-model) and model pages for [Astra](https://developers.openai.com/api/docs/models/gpt-6-astra), [Sol](https://developers.openai.com/api/docs/models/gpt-6-sol), [Luna](https://developers.openai.com/api/docs/models/gpt-6-luna), and [GPT-6.1 Sol](https://developers.openai.com/api/docs/models/gpt-6.1-sol).\n\n## Fast mode\n\nFast mode is a service tier, not a model id. Prefer flags:\n\n```sh\nsummarize URL --model openai/gpt-5.5 --fast --thinking medium\nsummarize URL --model openai/gpt-5.4 --service-tier fast --thinking low\n```\n\nCompatibility aliases:\n\n- `--model gpt-fast` / `--model fast`: `openai/gpt-5.5` with fast service tier and medium thinking.\n- `--model openai/gpt-5.5-fast` or `--model openai/gpt-5.4-mini-fast`: strip the `-fast` suffix for the API model id and use fast service tier.\n- `--model codex-fast`: explicit Codex CLI fast preset.\n\n## Env\n\n- `OPENAI_API_KEY` (required for `openai/...` models)\n- `OPENAI_USE_CHAT_COMPLETIONS` (optional; force chat completions)\n\n## Flags\n\n- `--model openai/<model>`\n- `--fast`\n- `--service-tier default|fast|priority|flex`\n- `--thinking none|low|medium|high|xhigh|max`\n- `--length short|medium|long|xl|xxl|<chars>`\n  - This is _soft guidance_ to the model (no hard truncation).\n- `--max-output-tokens <count>`\n  - Hard cap for output tokens (optional).\n- `--json` (includes prompt + summary in one JSON object)\n\n## Config\n\n```json\n{\n  \"openai\": {\n    \"serviceTier\": \"fast\",\n    \"thinking\": \"medium\"\n  }\n}\n```\n\n`openai.reasoningEffort` is the long-form alias for `openai.thinking`. Model presets can also set `serviceTier`, `thinking` / `reasoningEffort`, and `textVerbosity`.\n\nUse `\"serviceTier\": \"fast\"` in summarize config and model presets. OpenAI API requests map that to `service_tier=\"priority\"`; `\"flex\"` and explicit `\"priority\"` pass through as-is. Use `--service-tier default` to clear a configured tier for one run.\n\n## PDF inputs\n\n- When a PDF is provided and `--preprocess auto` is used, summarize sends the PDF as a file input via the OpenAI Responses API.\n- Document streaming is disabled for file inputs; non-streaming calls are used instead.\n","frontmatter":{"title":"OpenAI","kicker":"models","summary":"OpenAI model usage and flags.","read_when":["When changing OpenAI integration."]},"isInternal":false,"tokens":1129,"sizeBytes":4032},{"name":"openai.yaml","path":".agents/skills/summarize/agents/openai.yaml","rawUrl":"https://raw.githubusercontent.com/steipete/summarize/HEAD/.agents/skills/summarize/agents/openai.yaml","title":"Agents Skill","category":"anthropic-skill","format":"yaml","content":"interface:\n  display_name: \"Summarize\"\n  short_description: \"Summarize URLs, files, and media with the CLI\"\n  default_prompt: \"Use $summarize to extract or summarize this URL, file, or media input.\"\n","isInternal":false,"tokens":52,"sizeBytes":199},{"name":"SKILL.md","path":".agents/skills/summarize/SKILL.md","rawUrl":"https://raw.githubusercontent.com/steipete/summarize/HEAD/.agents/skills/summarize/SKILL.md","title":"summarize","category":"anthropic-skill","format":"markdown","content":"---\nname: summarize\ndescription: \"Summarize CLI: URLs, files, YouTube, transcripts, media, extraction, and JSON output.\"\n---\n\n# Summarize\n\nUse the `summarize` CLI as the canonical interface. Prefer a released binary on `PATH`; inside this repository, use `pnpm -s summarize` for the current checkout.\n\n## Start\n\n1. Confirm the command and current contract:\n\n   ```bash\n   summarize --version\n   summarize --help\n   ```\n\n2. Inspect model/provider readiness when a summary needs an LLM:\n\n   ```bash\n   summarize status\n   summarize status --json\n   ```\n\n3. Run the narrowest workflow below. Quote URLs and paths. Add `--timeout 2m` for slow remote or media inputs.\n\nNever print, request, or copy API-key values. `summarize status` reports availability without exposing secrets.\n\n## Summarize\n\nWeb page or remote document:\n\n```bash\nsummarize \"https://example.com/article\"\nsummarize \"https://example.com/report.pdf\" --length short\n```\n\nLocal file or stdin:\n\n```bash\nsummarize \"./report.pdf\"\nsummarize \"./recording.m4a\"\nprintf '%s\\n' \"Long text to summarize\" | summarize -\n```\n\nUse `--plain` for unrendered Markdown/text. Use `--language`, `--length`, `--prompt`, or `--prompt-file` only when the task requires an override. Use `--cli codex`, `--cli claude`, or another installed CLI provider when the user requests that provider or no direct API provider is configured.\n\n## Extract without a summary\n\nUse `--extract` to stop after extraction or transcription:\n\n```bash\nsummarize \"https://example.com/article\" --extract --format md\nsummarize \"./report.pdf\" --extract --format md\nsummarize \"https://youtu.be/VIDEO_ID\" --extract --format md\n```\n\n`--extract` does not support stdin. Extraction can still call configured transcription, OCR, Firecrawl, or Markdown services; it only skips the final summary call. `--markdown-mode llm` also invokes an LLM to reshape extracted text.\n\n## YouTube, audio, and video\n\nDefault transcript selection:\n\n```bash\nsummarize \"https://youtu.be/VIDEO_ID\"\nsummarize \"https://youtu.be/VIDEO_ID\" --extract --format md --timestamps\n```\n\nUse `--youtube web` to require web captions or `--youtube yt-dlp` to require the download/transcription path. Keep `auto` unless the user needs a specific source.\n\nLocal or remote audio/video:\n\n```bash\nsummarize \"./interview.mp3\" --extract\nsummarize \"./interview.mp4\" --extract --timestamps\nsummarize \"./interview.mp3\" --extract --diarize\n```\n\n`--transcriber auto` is the default. Use an explicit transcriber only when requested or diagnosing a provider. Diarization may require configured ElevenLabs or OpenAI access. Speaker identification is a separate opt-in step; do not infer identities without evidence.\n\nFor slides:\n\n```bash\nsummarize \"https://youtu.be/VIDEO_ID\" --slides\nsummarize \"./talk.mp4\" --slides --extract\n```\n\nSlide extraction may require `yt-dlp`; OCR requires `tesseract`.\n\n## JSON for automation\n\nUse JSON when another command or agent will parse the result:\n\n```bash\nsummarize \"https://example.com\" --json --metrics off > result.json\njq -r '.summary // .extracted.content // empty' result.json\n```\n\nThe stable top-level envelope contains `input`, `env`, `extracted`, `prompt`, `llm`, `metrics`, and `summary`. `summary` or `llm` can be `null` when extraction or a no-model path handles the input. In `--extract --json` mode, read extracted text from `.extracted.content`.\n\nJSON stays on stdout. Progress, warnings, and finish metrics stay on stderr. Do not merge stderr into stdout before parsing. Use `--metrics detailed` only when the task needs usage details.\n\n## Configuration and dependencies\n\nPrecedence: CLI flags, process environment, `~/.summarize/config.json`, built-in defaults. Prefer flags for one run; change config only when the user asks for a persistent default.\n\nUseful diagnostics:\n\n```bash\nsummarize status --verbose\nsummarize status --probe\nsummarize \"INPUT\" --verbose\n```\n\nPlain web summaries need no media tools. Media paths may use `ffmpeg`, `yt-dlp`, local Whisper/ONNX, or configured cloud transcription. Website fallback may use Firecrawl. Confirm the exact missing capability from the error before installing tools or changing config.\n\nInputs may be sent to the selected model, extraction, OCR, or transcription provider. For confidential material, confirm the approved provider or use an approved local path before running the command.\n\n## Verify\n\nAfter every run:\n\n- Require exit status `0`.\n- Require non-empty summary or extracted content.\n- For JSON, parse stdout with `jq` or another JSON parser.\n- For source-sensitive work, inspect `extracted`, `llm`, and stderr diagnostics rather than assuming the selected path.\n- Re-run the exact final command after changing provider, config, or flags.\n\nFor current option details, run `summarize --help` and read the repository documentation:\n\n- [Quickstart](../../../docs/quickstart.md)\n- [Main command](../../../docs/commands/summarize.md)\n- [Configuration](../../../docs/config.md)\n- [YouTube](../../../docs/youtube.md)\n- [Media](../../../docs/media.md)\n- [Extraction](../../../docs/extract-only.md)\n\n## Ownership\n\nThis file is the canonical agent workflow for the Summarize product. Keep generic agent workflows in `openclaw/agent-skills`; keep Summarize CLI behavior here. Downstream integrations should link to this file at a released tag or pinned commit and retain only their packaging or integration-specific notes. Do not maintain a second broad command guide downstream.\n","frontmatter":{"name":"summarize","description":"Summarize CLI: URLs, files, YouTube, transcripts, media, extraction, and JSON output."},"isInternal":false,"tokens":1280,"sizeBytes":5436},{"name":"daemon.md","path":"docs/commands/daemon.md","rawUrl":"https://raw.githubusercontent.com/steipete/summarize/HEAD/docs/commands/daemon.md","title":"Command: /daemon","category":"command-prompt","format":"markdown","content":"---\ntitle: summarize daemon\npermalink: /docs/commands/daemon.html\nkicker: command\nsummary: \"Manage the local daemon and Chrome Native Messaging bridge used by the Side Panel.\"\n---\n\n# `summarize daemon`\n\n```text\nsummarize daemon <subcommand> [options]\n```\n\nManages the local HTTP daemon and its browser integration. The daemon binds to `127.0.0.1` only and requires a shared bearer token. Chrome reaches it through an optional exact-ID Native Messaging host; Firefox retains its existing loopback integration. The daemon autostarts via the right service manager for your platform.\n\n| Platform | Service               |\n| -------- | --------------------- |\n| macOS    | LaunchAgent (launchd) |\n| Linux    | systemd user service  |\n| Windows  | Scheduled Task        |\n\nIf you only use the CLI, you don't need any of this.\n\n## Subcommands\n\n### `install`\n\nInstall or upgrade the autostart service, write `~/.summarize/daemon.json`, and register Chrome native host `com.steipete.summarize` on macOS/Linux.\n\n```bash\nsummarize daemon install --token <TOKEN>\nsummarize daemon install --token <TOKEN> --port 8787\nsummarize daemon install --token <TOKEN> --dev --extension-id <UNPACKED_ID>\n```\n\n`--token <token>` is **required** on first install; the extension prints one after pairing. Re-running `install` with a new token adds another paired browser instead of invalidating the old one. The native host manifest allows only Chrome Web Store extension ID `cejgnmmhbbpdmjnfppjdfkocebngehfg`.\n\n### `restart`\n\nRestart the autostart service. Useful after upgrading summarize or editing `daemon.json`.\n\n```bash\nsummarize daemon restart\n```\n\n### `status`\n\nProbe the autostart service, Chrome native-host registration, and the running daemon's health endpoint.\n\n```bash\nsummarize daemon status\n```\n\n### `uninstall`\n\nUnload the autostart service and remove the user-level Chrome native host. On macOS the daemon plist is moved to Trash so you can undo.\n\n```bash\nsummarize daemon uninstall\n```\n\n### `run`\n\nRun the daemon in the foreground. The autostart entry uses this internally; use it directly inside containers, on systems without launchd/systemd, or while debugging.\n\n```bash\nsummarize daemon run --port 8787\n```\n\n## Options\n\n`--port <n>`\n: TCP port. Default `8787`. For a non-default port, set the same value in the extension under **Options → Runtime → Daemon → Port**. The native host reads `daemon.json` and rejects mismatched requests.\n\n`--token <token>`\n: Bearer token. Required for `install`; also accepted by `run`, which adds it alongside the stored tokens for that run (required when no `daemon.json` exists). Stored in `~/.summarize/daemon.json` (mode `0600`).\n\n`--dev`\n: Install a service that runs `src/cli.ts` via Node's native TypeScript support from the current repo. Useful while hacking on the daemon — don't ship it to users.\n\n`--extension-id <id>`\n: With `--dev`, bind the native host to an unpacked Chrome extension ID. Production installs always use the exact Web Store ID.\n\n## HTTP endpoints\n\nThe daemon is documented in detail in [Chrome extension](../chrome-extension.md) and [Agent / daemon](../agent.md). At a glance:\n\n- `POST /v1/summarize` — start a run. Bearer-auth required. Returns `{ ok, id }` JSON (`coalesced: true` when it joins an in-flight run for the same request).\n- `GET /v1/summarize/{id}/events` — SSE stream of progress events and the final result for a run.\n- `GET /health` — health probe (used by `status`).\n\n## Files\n\n`~/.summarize/daemon.json`\n: Bearer token(s), port, and an env snapshot captured at install (includes provider API keys). Mode `0600`.\n\n`~/.summarize/daemon.log`\n: Rolling log written by the autostart service.\n\n## Notes\n\n- **Containers** — `install` starts the daemon for the current container session but does not register a Scheduled Task / unit. Run `summarize daemon run` from your entrypoint. Do not expose the port as a Chrome Native Messaging substitute.\n- **Token rotation** — running `install --token <NEW>` adds a new paired browser; old browsers keep working. Edit `daemon.json` by hand to revoke.\n- **Multiple installs** — only one daemon per user. Reinstall to upgrade; omitting `--port` preserves the configured port.\n- **Windows** — the npm-installed CLI still needs a packaged native-host `.exe`; do not route daemon traffic through the Direct-provider loopback grants as a workaround. Direct and Browser modes continue to work.\n\n## See also\n\n- [Chrome extension](../chrome-extension.md) — pairing flow + Side Panel UI.\n- [Agent / daemon](../agent.md) — automation surface.\n","frontmatter":{"title":"summarize daemon","permalink":"/docs/commands/daemon.html","kicker":"command","summary":"Manage the local daemon and Chrome Native Messaging bridge used by the Side Panel."},"isInternal":false,"tokens":1096,"sizeBytes":4570},{"name":"index.md","path":"docs/commands/index.md","rawUrl":"https://raw.githubusercontent.com/steipete/summarize/HEAD/docs/commands/index.md","title":"Command: /index","category":"command-prompt","format":"markdown","content":"---\ntitle: Commands\npermalink: /docs/commands/\nkicker: reference\nsummary: \"Every summarize subcommand and flag, with examples.\"\n---\n\n# Command reference\n\n`summarize` is one binary with a handful of subcommands. The default subcommand is `summarize` itself — the one you use 99% of the time. The others wrap related tooling.\n\n## Subcommands\n\n- [`summarize`](summarize.md) — main command. Takes a URL, file, or stdin and produces a summary or extracted content.\n- [`summarize status`](../cli.md#cli-discovery) — print the selected model, enabled providers, and runtime status.\n- [`summarize slides`](slides.md) — extract scene-change keyframes from a YouTube URL, direct video URL, or local video file into PNGs (and optional OCR text). Standalone version of the `--slides` flag.\n- [`summarize transcriber`](transcriber.md) — set up local ONNX transcription (Parakeet, Canary). Prints the env vars you need.\n- [`summarize daemon`](daemon.md) — manage the local HTTP daemon that the Chrome Side Panel talks to. Subcommands: `install`, `restart`, `status`, `uninstall`, `run`.\n- [`summarize refresh-free`](refresh-free.md) — scan OpenRouter `:free` models, write working candidates to `~/.summarize/config.json`.\n- `summarize help [topic]` — print help for the CLI or a subcommand (`slides`, `status`, `daemon`, `transcriber`, `refresh-free`).\n\n## Output discipline\n\nAll subcommands keep the same output discipline — straight from gogcli's playbook so pipes and scripts stay parseable:\n\n- **stdout:** the result. Plain text, Markdown, JSON, or files (slides only).\n- **stderr:** progress, prompts, warnings, and errors.\n- `--json` produces a stable envelope on stdout.\n- `--no-color` strips ANSI; `--plain` skips ANSI/OSC rendering for Markdown.\n\n## Global behavior\n\nOnly two flags apply to every subcommand; the rest are per-command:\n\n| Flag                          | Where it works                                                                                                                             |\n| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |\n| `--locale <locale>`           | Everywhere. Interface language: `auto` plus the shipped UI locales (`SUMMARIZE_LOCALE` too).                                               |\n| `--help`                      | Everywhere (`summarize help <topic>` prints topic help).                                                                                   |\n| `-V`, `--version`             | `summarize`, `summarize slides`.                                                                                                           |\n| `--json`                      | `summarize`, `summarize slides`, `summarize status`.                                                                                       |\n| `--no-color`                  | `summarize`, `summarize status`, `summarize refresh-free`, `summarize transcriber`.                                                        |\n| `--theme <name>`              | `summarize`, `summarize slides`, `summarize transcriber` (`SUMMARIZE_THEME` env var also works).                                           |\n| `--verbose` / `--debug`       | `summarize`, `summarize slides`, `summarize refresh-free`, `summarize daemon`, `summarize transcriber`. `status` accepts `--verbose` only. |\n| `--metrics off\\|on\\|detailed` | `summarize` only.                                                                                                                          |\n| `--timeout <duration>`        | `summarize`, `summarize slides`.                                                                                                           |\n\n## Exit codes\n\n| Code  | Meaning                                                                     |\n| ----- | --------------------------------------------------------------------------- |\n| `0`   | Success.                                                                    |\n| `1`   | Any failure — usage errors, extraction, model, network, and timeouts alike. |\n| `130` | Interrupted by SIGINT (Ctrl+C).                                             |\n| `143` | Terminated by SIGTERM.                                                      |\n\n`summarize daemon` and `summarize transcriber` still exit `1` when the underlying service install (launchd, systemd, schtasks) fails; the platform's own error text is included in the message — check `--verbose` output for the raw error.\n","frontmatter":{"title":"Commands","permalink":"/docs/commands/","kicker":"reference","summary":"Every summarize subcommand and flag, with examples."},"isInternal":false,"tokens":899,"sizeBytes":4561},{"name":"refresh-free.md","path":"docs/commands/refresh-free.md","rawUrl":"https://raw.githubusercontent.com/steipete/summarize/HEAD/docs/commands/refresh-free.md","title":"Command: /refresh-free","category":"command-prompt","format":"markdown","content":"---\ntitle: summarize refresh-free\npermalink: /docs/commands/refresh-free.html\nkicker: command\nsummary: \"Scan OpenRouter :free models and write working candidates to config.\"\n---\n\n# `summarize refresh-free`\n\n```text\nsummarize refresh-free [--runs 2] [--smart 3] [--min-params 27b]\n                       [--max-age-days 180] [--set-default] [--verbose]\n```\n\nProbes [OpenRouter](https://openrouter.ai)'s catalog for `:free` models, runs them on a small benchmark, and writes the working ones to `models.free` in `~/.summarize/config.json`. Useful when you want to use `--model free` without picking a specific OpenRouter slug.\n\nNeeds `OPENROUTER_API_KEY` in the environment.\n\n## What it does\n\n1. Pulls the OpenRouter model catalog.\n2. Filters to models tagged `:free` that meet `--min-params` and `--max-age-days`.\n3. Benchmarks every candidate once against a sanity prompt, then probes the shortlisted candidates `--runs` more times; ranks by `--smart` heuristics (latency, completion length, refusal rate).\n4. Writes the survivors to `models.free` in `~/.summarize/config.json`.\n5. With `--set-default`, also sets top-level `model` to `free`.\n\nAfter the run, `summarize \"https://example.com\" --model free` rotates through the saved list until one succeeds.\n\n## Flags\n\n`--runs <n>`\n: Extra refinement probes per shortlisted candidate after the initial benchmark run (`1 + --runs` total). `0` skips refinement. Default `2`.\n\n`--smart <n>`\n: How many top candidates to keep. Default `3`.\n\n`--min-params <size>`\n: Minimum parameter count. Accepts `7b`, `27b`, `70b`, etc. Default `27b`.\n\n`--max-age-days <n>`\n: Reject models older than N days based on OpenRouter's metadata. Default `180`.\n\n`--set-default`\n: Also set `model: \"free\"` at the top level of `~/.summarize/config.json`.\n\n`--verbose` / `--debug`\n: Per-candidate progress, timings, and rejection reasons on stderr.\n\n## Examples\n\n```bash\n# Quick refresh; keep the best 3 free models ≥27B, ≤180d old.\nsummarize refresh-free\n\n# Looser filter — accept smaller / older models.\nsummarize refresh-free --min-params 7b --max-age-days 365\n\n# Refresh and also set the default model.\nsummarize refresh-free --set-default\n\n# Verbose ranking output for debugging.\nsummarize refresh-free --runs 3 --smart 5 --verbose\n```\n\n## Output\n\n`~/.summarize/config.json` is updated in place. The relevant section ends up looking like:\n\n```json\n{\n  \"models\": {\n    \"free\": [\"openai/gpt-oss-120b:free\", \"z-ai/glm-4.6:free\", \"deepseek/deepseek-r1:free\"]\n  }\n}\n```\n\nA short summary of survivors and rejected candidates is printed on stderr. The only stdout line is the localized config-write confirmation, e.g. `Wrote /Users/you/.summarize/config.json (models.free)` — a sentence containing the path, not a bare path value.\n\nColor follows the rest of the CLI: `FORCE_COLOR=0` disables it, while a nonzero `FORCE_COLOR` takes precedence over `NO_COLOR`. Without an override, color requires a capable terminal.\n\n## See also\n\n- [LLM overview](../llm.md) — `--model` syntax, including `free`.\n- [Auto selection](../model-auto.md) — how `auto` picks across providers.\n- [Config](../config.md) — full schema for `~/.summarize/config.json`.\n","frontmatter":{"title":"summarize refresh-free","permalink":"/docs/commands/refresh-free.html","kicker":"command","summary":"Scan OpenRouter :free models and write working candidates to config."},"isInternal":false,"tokens":839,"sizeBytes":3175},{"name":"slides.md","path":"docs/commands/slides.md","rawUrl":"https://raw.githubusercontent.com/steipete/summarize/HEAD/docs/commands/slides.md","title":"Command: /slides","category":"command-prompt","format":"markdown","content":"---\ntitle: summarize slides\npermalink: /docs/commands/slides.html\nkicker: command\nsummary: \"Extract scene-change keyframes from a video source into PNG files.\"\n---\n\n# `summarize slides`\n\n```text\nsummarize slides <source> [flags]\n```\n\nExtracts slide-shaped keyframes from a YouTube URL, direct video URL, or local video file using FFmpeg scene detection. Native ffmpeg is preferred; bundled FFmpeg WebAssembly is used when native `ffmpeg`/`ffprobe` are unavailable. Output is a directory of PNGs (and optional OCR text). This is the standalone form of the `--slides` flag on the main command — useful when you only want the slides without a summary.\n\n## Synopsis\n\n```bash\nsummarize slides \"https://youtu.be/...\"\nsummarize slides \"https://youtu.be/...\" --render auto\nsummarize slides \"https://youtu.be/...\" --slides-ocr -o ./out\nsummarize slides \"https://example.com/lecture.mp4\" --slides-max 12\nsummarize slides ./lecture.mp4 --slides-max 12\n```\n\n## Requirements\n\n- Bundled FFmpeg WebAssembly, or native `ffmpeg` on PATH for faster extraction and broader codec support.\n- `yt-dlp` on PATH for YouTube URLs.\n- `tesseract` on PATH for `--slides-ocr`.\n\nIf a required tool is missing, summarize prints a clear warning and exits non-zero.\n\n## Flags\n\n`--slides-ocr`\n: Run OCR on every extracted slide. Stores `ocrText` and `ocrConfidence` in `slides.json` and the JSON response.\n\n`--slides-dir <dir>`\n: Output base directory. Default: `./slides`. A per-video subfolder is created inside.\n\n`-o, --output <dir>`\n: Alias for `--slides-dir`.\n\n`--slides-scene-threshold <value>`\n: Scene detection threshold, `0.1`–`1.0`. Default `0.3`. Lower values detect more scenes (more slides); higher values are stricter.\n\n`--slides-max <count>`\n: Cap on extracted slides. Default `6`.\n\n`--slides-min-duration <seconds>`\n: Minimum gap between slides. Default `2`.\n\n`--render <mode>`\n: Inline render of thumbnails: `auto`, `kitty`, `iterm`, `none`. Default `none` — paths are printed instead.\n\n`--theme <name>`\n: Pick a CLI theme.\n\n`--timeout <duration>`\n: Per-operation timeout setting. Default `2m`; not an overall wall-clock deadline. yt-dlp downloads and FFmpeg scene detection allow at least `5m`, and individual extraction/probe steps have their own limits.\n\n`--no-cache`\n: Force re-download and re-extraction (bypasses both caches).\n\n`--json`\n: JSON envelope on stdout. Disables inline rendering.\n\n`--verbose` / `--debug`\n: Detailed progress on stderr.\n\n`-V`, `--version`\n: Print version and exit.\n\n## Output\n\nEach run writes a directory like:\n\n```text\nslides/<source-id>/\n  slide_0001_18.60s.png\n  slide_0002_42.20s.png\n  ...\n  slides.json\n```\n\nThe filenames include the slide index and timestamp. `slides.json` records the manifest, including OCR results when requested; OCR does not create separate text files. `ocrConfidence` uses a 0–1 scale.\n\nIn `--json` mode, stdout contains an envelope like this (additional extraction metadata omitted):\n\n```json\n{\n  \"ok\": true,\n  \"slides\": {\n    \"sourceUrl\": \"https://example.com/lecture.mp4\",\n    \"slidesDir\": \"/absolute/path/slides/<id>\",\n    \"slides\": [\n      {\n        \"index\": 1,\n        \"timestamp\": 18.6,\n        \"imagePath\": \"/absolute/path/slides/<id>/slide_0001_18.60s.png\",\n        \"ocrText\": \"Recognized slide text\",\n        \"ocrConfidence\": 0.92\n      }\n    ]\n  }\n}\n```\n\n## Inline rendering\n\n`--render auto` detects Kitty (`KITTY_WINDOW_ID`) and iTerm (`TERM_PROGRAM=iTerm.app`) and uses the matching image protocol. On unsupported terminals, slides are listed by path instead.\n\n## Examples\n\n```bash\n# Quick preview in iTerm/Kitty.\nsummarize slides \"https://youtu.be/...\" --render auto\n\n# Big lecture, more granular cuts.\nsummarize slides \"https://youtu.be/...\" \\\n  --slides-max 24 --slides-scene-threshold 0.2\n\n# Pipe-friendly JSON for an automation.\nsummarize slides \"https://youtu.be/...\" --json | jq '.slides.slides[].imagePath'\n\n# Force re-extraction after editing the source video.\nsummarize slides \"./talk.mp4\" --no-cache -o ./out\n```\n\n## See also\n\n- [Slides mode](../slides.md) — the inline `--slides` flag on the main command.\n- [Slides rendering flow](../slides-rendering-flow.md) — pipeline internals.\n","frontmatter":{"title":"summarize slides","permalink":"/docs/commands/slides.html","kicker":"command","summary":"Extract scene-change keyframes from a video source into PNG files."},"isInternal":false,"tokens":1085,"sizeBytes":4165},{"name":"summarize.md","path":"docs/commands/summarize.md","rawUrl":"https://raw.githubusercontent.com/steipete/summarize/HEAD/docs/commands/summarize.md","title":"Command: /summarize","category":"command-prompt","format":"markdown","content":"---\ntitle: summarize\npermalink: /docs/commands/summarize.html\nkicker: command\nsummary: \"Main command. URL, file, or stdin → clean text → summary.\"\n---\n\n# `summarize`\n\n```text\nsummarize [input] [flags]\n```\n\nTakes a URL, local file path, or `-` for stdin and produces a summary. With `--extract`, prints cleaned content instead of summarizing; stdin is not supported in extract mode.\n\n## Synopsis\n\n```bash\nsummarize \"https://example.com/article\"\nsummarize ./report.pdf --model openai/gpt-5-mini\nsummarize \"https://youtu.be/...\" --slides --slides-ocr\npbpaste | summarize -\nsummarize \"https://example.com\" --extract --format md > clean.md\nsummarize \"https://example.com\" --json --metrics detailed\n```\n\n## Input\n\n- **URL** — http/https. YouTube, podcast hosts, generic articles, raw media.\n- **File path** — PDF, image, audio, video, plain text, Markdown, HTML.\n- **`-`** — read content from stdin (text or binary).\n\nIf `[input]` is omitted, summarize prints concise help and exits.\n\n## Flags\n\n### Extraction\n\n`--extract`\n: Print extracted content and exit. No LLM call. Supports URLs, YouTube/direct media, local audio/video, and local PDFs; `-` stdin is not supported. The `--extract-only` alias is hidden but still works.\n: Extraction can still use configured remote transcription, OCR, or Markdown providers for media/PDF inputs.\n\n`--format <format>`\n: `md`/`markdown` or `text`/`txt`/`plain`. Controls website extraction format and whether files are preprocessed to Markdown for model compatibility. Default: `text`. Default in `--extract` mode for URLs: `md`.\n\n`--firecrawl <mode>`\n: `off`, `auto`, `always`. `auto` falls back to Firecrawl when local extraction looks blocked or thin. Needs `FIRECRAWL_API_KEY`.\n\n`--preprocess <mode>`\n: `off`, `auto`, `always`. Default `auto`. Controls `markitdown` usage for files. `always` only affects file inputs.\n: Image-only PDFs can retry through OpenAI vision OCR when `OPENAI_API_KEY` is set. Set `MARKITDOWN_OCR_MODEL` to choose the OCR model, or `MARKITDOWN_OCR_DPI` to tune rendered page size.\n\n`--markdown-mode <mode>`\n: `off`, `auto`, `llm`, `readability`. For websites: HTML → Markdown strategy. For YouTube/transcripts: `llm` formats raw transcripts into clean Markdown with headings. The `--markdown` alias is hidden and deprecated.\n\n`--max-extract-characters <count>`\n: Cap printed characters in `--extract` mode. Default: unlimited.\n\n### YouTube / video\n\n`--youtube <mode>`\n: `auto`, `web`, `apify`, `yt-dlp`, `no-auto` (skip auto-generated captions). Default `auto`.\n\n`--transcriber <name>`\n: Select the local transcription stage: `auto`, `whisper`, `parakeet`, `canary`. Default `auto` — Groq still runs first when keyed, then local ONNX/`whisper.cpp`, then cloud fallbacks.\n\n`--video-mode <mode>`\n: `auto`, `transcript`, `understand`. `understand` prefers vision/video understanding when supported.\n\n`--embedded-video <mode>`\n: `auto`, `off`, `prefer`, `both`. Controls embedded YouTube handling on regular web pages: `off` keeps the article text only, `prefer` favors the video transcript, `both` combines labeled article + transcript sections. Default `auto` — uses only high-confidence primary embeds. See [Website mode](../website.md).\n\n`--timestamps`\n: Include timestamps in transcripts when available.\n\n`--diarize [provider]`\n: Add speaker labels to YouTube, local audio/video, or direct media URLs. Provider: `auto`, `elevenlabs`, or `openai`.\n\n`--identify-speakers` / `--no-identify-speakers`\n: Resolve generic diarization labels to names, or disable configured resolution for one run. Uses authoritative anchors and OpenAI GPT-5.5 context inference.\n\n`--speaker-profile <name>`\n: Select a reusable profile from `speakers.profiles` in the config file.\n\n`--speaker-at <timestamp=name>`\n: Name the speaker active at a timestamp. Repeat the flag for multiple speakers.\n\n`--remember-speakers`\n: Atomically persist resolved names, anchors, and a transcript-hash-guarded source mapping under the selected profile.\n\n### Slides\n\n`--slides [on|off]` / `--no-slides`\n: Extract slides from a YouTube URL, direct video URL, or local video file and render inline alongside the summary. Combine with `--extract` to interleave slides in the full transcript. See [Slides mode](../slides.md).\n: The optional value accepts boolean words (`on`/`off`, `true`/`false`, `yes`/`no`, `1`/`0`); anything else is rejected. Use `--no-slides` to disable slide extraction enabled in the config file for one run.\n\n`--slides-ocr` / `--no-slides-ocr`\n: Run OCR on extracted slides. Requires `tesseract`.\n: Use `--no-slides-ocr` to disable configured slide OCR while retaining slide extraction.\n\n`--slides-debug`\n: Print slide image paths instead of rendering inline (useful in non-image terminals).\n\n`--slides-dir <dir>`\n: Output directory base. Default `./slides`.\n\n`--slides-scene-threshold <value>`\n: Scene detection threshold, `0.1`–`1.0`. Default `0.3`.\n\n`--slides-max <count>`\n: Cap on extracted slides. Default `6`.\n\n`--slides-min-duration <seconds>`\n: Minimum gap between slides. Default `2`.\n\n### Summary control\n\n`--length <length>`\n: `short`, `medium`, `long`, `xl`, `xxl` (or `s`/`m`/`l`) or a character cap like `20000` or `20k`. Default `long`. Override globally via `output.length` in [Config](../config.md).\n\n`--force-summary`\n: Always run the LLM, even when extracted content is shorter than the requested length.\n\n`--language, --lang <language>`\n: `auto`, `en`, `de`, `english`, `german`, … Default `auto` (matches source). Configurable via `output.language`.\n\n`--locale <locale>`\n: CLI interface language: `auto` plus the shipped UI locales (`en`, `de`, `fr`, `es`, `it`, `pt-BR`, `nl`, `pl`, `ru`, `ja`, `zh-Hans`, `zh-Hant`, `ko`, `tr`). Default follows the system locale with English fallback. `SUMMARIZE_LOCALE` also works. See [Localization](../localization.md).\n\n`--prompt <text>` / `--prompt-file <path>`\n: Override the summary prompt. Content is appended after the override.\n\n### Models\n\n`--model <model>`\n: Model id. `auto`, `<config-preset>`, `cli/<provider>/<model>`, `xai/...`, `openai/...`, `nvidia/...`, `minimax/...`, `google/...`, `anthropic/...`, `zai/...`, `ollama/<model>` (local Ollama), `openclaw/<model>` (shorthand for `cli/openclaw/<model>`), or `openrouter/<author>/<slug>`. Default `auto`. See [LLM overview](../llm.md).\n\n`--cli [provider]`\n: Use a logged-in CLI provider: `claude`, `gemini`, `codex`, `agent`, `openclaw`, `opencode`, `copilot`, `agy`, `pi`, `devin`, `grok`. Equivalent to `--model cli/<provider>`. Without a value: enable CLI providers in auto-selection.\n\n`--thinking <effort>`\n: Reasoning effort. `none`, `low`, `medium`, `high`, `xhigh`, `max` (GPT-6 models). Aliases: `off`, `min`, `med`, `mid`, `x-high`, `extra-high`. Affects reasoning-capable models on the dispatched provider (OpenAI, Anthropic Claude 4+, pi CLI).\n\n`--service-tier <tier>`\n: OpenAI service tier. `default`, `fast`, `priority`, `flex`. Maps to `service_tier` on the request.\n\n`--fast`\n: Shortcut for OpenAI `service_tier=priority`. Same effect as `--service-tier fast`.\n\n`--max-output-tokens <count>`\n: Hard cap for LLM output tokens. Accepts `2000`, `2k`. Overrides provider defaults.\n\n`--retries <count>`\n: LLM retry attempts after timeouts or transient API failures. `0`–`5`. Default `1`.\n\n### Output\n\n`--json`\n: Structured JSON envelope on stdout. Includes prompt + metrics. Disables streaming.\n\n`--stream <mode>`\n: `auto`, `on`, `off`. Default `auto` (TTY-only). Disabled in `--json` mode.\n\n`--plain`\n: Keep raw text/Markdown — no ANSI/OSC rendering.\n\n`--no-color`\n: Disable ANSI colors.\n\n`--width <columns>`\n: Override terminal width for Markdown rendering. Default: auto-detect, max 120.\n\n`--theme <name>`\n: Pick a CLI theme. Run `summarize --help` for the list. Env: `SUMMARIZE_THEME`.\n\n### Cache\n\n`--no-cache`\n: Bypass the summary (LLM) cache. Media + transcript caches stay enabled.\n\n`--no-media-cache`\n: Disable the media download cache (`yt-dlp` outputs).\n\n`--cache-stats`\n: Print cache stats and exit.\n\n`--clear-cache`\n: Delete the cache database and exit.\n\nSee [Cache internals](../cache.md) for what's cached and where.\n\n### Diagnostics\n\n`--verbose`\n: Detailed progress on stderr.\n\n`--debug`\n: Alias for `--verbose`. Also defaults `--metrics` to `detailed`.\n\n`--metrics <mode>`\n: `off`, `on`, `detailed`. Default `on`. Adds a compact second-line breakdown on stderr when `detailed`.\n\n`--timeout <duration>`\n: Per-operation timeout for content fetching and LLM requests (not an overall wall-clock deadline). `30`, `30s`, `2m`, `5000ms`. Default `2m`.\n\n`-V`, `--version`\n: Print version and exit.\n\n## Examples\n\n```bash\n# Extracted plain text from a URL.\nsummarize \"https://example.com\" --extract\n\n# Extracted Markdown — prefers Firecrawl when configured.\nsummarize \"https://example.com\" --extract --format md\n\n# YouTube transcript as cleanly-formatted Markdown.\nsummarize \"https://www.youtube.com/watch?v=...\" \\\n  --extract --format md --markdown-mode llm\n\n# ElevenLabs diarization with verified speaker names.\nsummarize \"https://www.youtube.com/watch?v=...\" --extract \\\n  --diarize elevenlabs --identify-speakers \\\n  --speaker-profile my-podcast --speaker-at \"0:12=Host Name\" --remember-speakers\n\n# Inline slides + summary.\nsummarize \"https://www.youtube.com/watch?v=...\" --slides\n\n# Full transcript + inline slides.\nsummarize \"https://www.youtube.com/watch?v=...\" --slides --extract\n\n# Hard caps + a specific model.\nsummarize \"https://example.com\" \\\n  --length 20k --max-output-tokens 2k --timeout 2m \\\n  --model openai/gpt-5-mini\n\n# OpenAI fast tier with reasoning.\nsummarize \"https://example.com\" \\\n  --model openai/gpt-5.5 --fast --thinking medium\n\n# Config preset (alias defined in ~/.summarize/config.json).\nsummarize \"https://example.com\" --model mymodel\n\n# Strict JSON for scripts.\nsummarize \"https://example.com\" --json --verbose\n\n# Summarize the clipboard.\npbpaste | summarize -\n```\n\n## Environment\n\nThe provider keys and binary paths picked up at runtime are listed in [LLM overview](../llm.md#env). `SUMMARIZE_MODEL` overrides the default model selection; `SUMMARIZE_THEME` picks the theme; `SUMMARIZE_LOCALE` picks the interface language.\n\n## See also\n\n- [LLM overview](../llm.md) — how `--model` resolves to a provider.\n- [Website mode](../website.md), [YouTube](../youtube.md), [Media + podcasts](../media.md).\n- [Cache](../cache.md), [Firecrawl](../firecrawl.md).\n- [Config](../config.md) for persistent defaults.\n","frontmatter":{"title":"summarize","permalink":"/docs/commands/summarize.html","kicker":"command","summary":"Main command. URL, file, or stdin → clean text → summary."},"isInternal":false,"tokens":2802,"sizeBytes":10441},{"name":"transcriber.md","path":"docs/commands/transcriber.md","rawUrl":"https://raw.githubusercontent.com/steipete/summarize/HEAD/docs/commands/transcriber.md","title":"Command: /transcriber","category":"command-prompt","format":"markdown","content":"---\ntitle: summarize transcriber\npermalink: /docs/commands/transcriber.html\nkicker: command\nsummary: \"Set up local ONNX transcription (Parakeet, Canary).\"\n---\n\n# `summarize transcriber`\n\n```text\nsummarize transcriber setup [--model parakeet|canary] [--theme <name>]\n```\n\nConfigures local ONNX transcription. The command **prints the env vars** you need to export — it doesn't write to your shell config. Once those vars are exported, `--transcriber auto` (or `SUMMARIZE_TRANSCRIBER=auto`) uses ONNX after Groq and before `whisper.cpp` and the remaining cloud fallbacks.\n\n## How auto picks a transcriber\n\nWhen `--transcriber auto` is set (default), summarize tries providers in this order:\n\n1. **Groq** — fastest cloud option. Needs `GROQ_API_KEY`.\n2. **Local ONNX** (Parakeet or Canary), then `whisper.cpp` — fully offline. ONNX needs the env vars from this command.\n3. **AssemblyAI / Gemini / OpenAI / FAL / Deepgram** — cloud fallbacks, in that order, gated by their respective API keys.\n\n`OPENAI_WHISPER_BASE_URL` changes the endpoint used by the OpenAI transcription stage; it is not a separate provider in the order above.\n\n## Subcommand\n\n### `summarize transcriber setup`\n\n`--model <name>`\n: `parakeet` (default) or `canary`. Picks which ONNX model the printed snippet targets.\n\n`--theme <name>`\n: CLI theme override.\n\nThe output is a labelled, copy-pasteable block of `export` lines for your shell. Re-run with the other model to switch.\n\n## Environment\n\nSet by the printed snippet:\n\n`SUMMARIZE_ONNX_PARAKEET_CMD`\n: Command to run Parakeet ONNX transcription. Use `{input}` as the audio-file placeholder.\n\n`SUMMARIZE_ONNX_CANARY_CMD`\n: Command to run Canary ONNX transcription. Use `{input}` as the audio-file placeholder.\n\n`SUMMARIZE_TRANSCRIBER`\n: Optional. Select the local stage with `auto`, `whisper`, `parakeet`, or `canary` without passing `--transcriber` every time.\n\n## Examples\n\n```bash\n# Default: Parakeet.\nsummarize transcriber setup\n\n# Set up Canary instead.\nsummarize transcriber setup --model canary\n\n# After exporting the printed vars:\nsummarize \"https://podcasts.apple.com/.../episode-...\" --transcriber parakeet\n```\n\n## See also\n\n- [ONNX transcription](../nvidia-onnx-transcription.md) — how to actually install the model + runtime.\n- [Transcript provider flow](../transcript-provider-flow.md) — full selection waterfall.\n","frontmatter":{"title":"summarize transcriber","permalink":"/docs/commands/transcriber.html","kicker":"command","summary":"Set up local ONNX transcription (Parakeet, Canary)."},"isInternal":false,"tokens":618,"sizeBytes":2359},{"name":"README.md","path":"packages/core/README.md","rawUrl":"https://raw.githubusercontent.com/steipete/summarize/HEAD/packages/core/README.md","title":"core Documentation","category":"plugin-manifest","format":"markdown","content":"# @steipete/summarize-core\n\nCore library for Summarize (content extraction + prompt builders).\n\n- CLI package: `@steipete/summarize`\n- Recommended imports (library use): `@steipete/summarize-core/content`, `@steipete/summarize-core/prompts`\n\nThe content entry point also exports DNS-pinned network helpers. `fetchWithDnsPinnedAddresses` accepts addresses attached with `attachDnsPinnedAddresses`; callers must validate those addresses first or use `createNetworkGuardedFetch` for validation. The transport honors cancellation from either a `Request` or its init options, returns null bodies for HEAD and HTTP 204/205/304, and rejects invalid HTTP responses through its promise.\n\nThe network guard revalidates every followed redirect and cancels discarded redirect bodies. Same-origin redirects retain request options and credentials; origin changes strip explicit authorization and cookie headers, including changes of scheme or port. Manual redirects remain available for the caller to consume.\n\nThe `@steipete/summarize-core/processes` entry point provides `signalTrackedProcess(child, signal)` for stopping one tracked command and its process tree, alongside `terminateTrackedProcesses(signal)` for all tracked commands. Use the per-command helper for deadlines so sibling work continues.\n","isInternal":false,"tokens":271,"sizeBytes":1292}],"systemPromptSnippet":"<yakaai_skills repo=\"steipete/summarize\">\n<!-- File: AGENTS.md (Tokens: ~550 | Category: root-instruction) -->\n# Summarize Guardrails\n\n- Hard rule: single source of truth = `~/Projects/summarize`; never commit in `vendor/summarize` (treat it as a read-only checkout).\n- Note: multiple agents often work in this folder. If you see files/changes you do not recognize, ignore them and list them at the end.\n\n## Workspace layout (note)\n\n- Monorepo (pnpm workspace).\n- Packages:\n  - `@steipete/summarize` = CLI + UX (TTY/progress/streaming). Depends on core.\n  - `@steipete/summarize-core` (`packages/core`) = library surface for programmatic use (Sweetistics etc). No CLI entrypoints.\n- Versioning: lockstep versions; publish order: core first, then CLI (`scripts/release.sh` / `RELEASING.md`).\n- Homebrew/core formula is not owned here; BrewTestBot autobumps releases about every 3h. Do not block or manually manage it; ship and continue.\n- Chrome Web Store: every release must upload the matching `dist-chrome/summarize-chrome-extension-v<version>.zip` to item `cejgnmmhbbpdmjnfppjdfkocebngehfg`, submit it for review with automatic publishing, and verify the exact pending/published version. Skip only when every shipped change is daemon-side and the packaged extension/companion contract is unchanged.\n- Dev:\n  - Build: `pnpm run build` (builds core first; also runs during install via `prepare`)\n  - Gate: `pnpm run check`\n  - Import from apps: prefer `@steipete/summarize-core` to avoid pulling CLI-only deps.\n- Dependencies: stable releases need a 7-day stabilization delay before adoption; prereleases remain excluded unless already adopted.\n- Daemon: restart with `pnpm summarize daemon restart`; verify via `pnpm summarize daemon status`.\n- Rebuild (extension + daemon): run **both** in order:\n  1. `pnpm -C apps/chrome-extension build`\n  2. `pnpm summarize daemon restart`\n- Extension tests:\n  - `pnpm -C apps/chrome-extension test:chrome` = supported automated path.\n  - Firefox Playwright extension tests are not reliable (`moz-extension://` limitation); default `test:firefox` runs a temporary-install smoke test.\n  - Use `pnpm -C apps/chrome-extension test:firefox:force` only for explicit diagnostics.\n- Commits: use `committer \"type: message\" <files...>` (Conventional Commits).\n\n<!-- File: docs/openai.md (Tokens: ~1129 | Category: root-instruction) -->\n---\ntitle: \"OpenAI\"\nkicker: \"models\"\nsummary: \"OpenAI model usage and flags.\"\nread_when:\n  - \"When changing OpenAI integration.\"\n---\n\n# OpenAI models\n\nUse OpenAI directly by choosing an `openai/...` model id.\n\nFor the full model/provider matrix, see `docs/llm.md`.\n\n## GPT-6\n\nUse the documented model ids: `openai/gpt-6-astra`, `openai/gpt-6-sol`, `openai/gpt-6-luna`, or `openai/gpt-6.1-sol`.\nSummarize uses the Responses API by default for direct OpenAI text and image requests, including streaming, and for PDF inputs. `OPENAI_USE_CHAT_COMPLETIONS=1` still selects Chat Completions for text and images.\nReasoning requests omit `temperature`, which GPT-6 rejects. GPT-6 Sol and Luna preserve temperature when explicitly using `--thinking none`; Astra and GPT-6.1 Sol require reasoning.\n\n```sh\nsummarize https://summarize.sh/ --model openai/gpt-6-astra --thinking medium --fast\nsummarize https://summarize.sh/ --model openai/gpt-6-sol --thinking medium\nsummarize https://summarize.sh/ --model openai/gpt-6-luna --thinking low\nsummarize https://summarize.sh/ --model openai/gpt-6.1-sol --thinking max\n```\n\nThese explicit model ids do not change the default model or existing presets.\nThe model picker and built-in pricing catalog include all four models. Standard input/output\nprices per million tokens are $10/$50 for Astra, $2/$10 for Sol and GPT-6.1 Sol, and $0.10/$0.50 for Luna.\nCost estimates use these standard rates; they do not include cache discounts, cache writes,\nfast/flex service tiers, or long-context premiums. See [OpenAI pricing](https://developers.openai.com/api/docs/pricing).\nAll four GPT-6 models support `low`, `medium`, `high`, `xhigh`, and `max`. Summarize accepts `max` only for these documented model ids.\nAn unsupported `--thinking none` request for Astra or GPT-6.1 Sol fails locally before sending an API request.\nSee OpenAI's [GPT-6 guide](https://developers.openai.com/api/docs/guides/latest-model) and model pages for [Astra](https://developers.openai.com/api/docs/models/gpt-6-astra), [Sol](https://developers.openai.com/api/docs/models/gpt-6-sol), [Luna](https://developers.openai.com/api/docs/models/gpt-6-luna), and [GPT-6.1 Sol](https://developers.openai.com/api/docs/models/gpt-6.1-sol).\n\n## Fast mode\n\nFast mode is a service tier, not a model id. Prefer flags:\n\n```sh\nsummarize URL --model openai/gpt-5.5 --fast --thinking medium\nsummarize URL --model openai/gpt-5.4 --service-tier fast --thinking low\n```\n\nCompatibility aliases:\n\n- `--model gpt-fast` / `--model fast`: `openai/gpt-5.5` with fast service tier and medium thinking.\n- `--model openai/gpt-5.5-fast` or `--model openai/gpt-5.4-mini-fast`: strip the `-fast` suffix for the API model id and use fast service tier.\n- `--model codex-fast`: explicit Codex CLI fast preset.\n\n## Env\n\n- `OPENAI_API_KEY` (required for `openai/...` models)\n- `OPENAI_USE_CHAT_COMPLETIONS` (optional; force chat completions)\n\n## Flags\n\n- `--model openai/<model>`\n- `--fast`\n- `--service-tier default|fast|priority|flex`\n- `--thinking none|low|medium|high|xhigh|max`\n- `--length short|medium|long|xl|xxl|<chars>`\n  - This is _soft guidance_ to the model (no hard truncation).\n- `--max-output-tokens <count>`\n  - Hard cap for output tokens (optional).\n- `--json` (includes prompt + summary in one JSON object)\n\n## Config\n\n```json\n{\n  \"openai\": {\n    \"serviceTier\": \"fast\",\n    \"thinking\": \"medium\"\n  }\n}\n```\n\n`openai.reasoningEffort` is the long-form alias for `openai.thinking`. Model presets can also set `serviceTier`, `thinking` / `reasoningEffort`, and `textVerbosity`.\n\nUse `\"serviceTier\": \"fast\"` in summarize config and model presets. OpenAI API requests map that to `service_tier=\"priority\"`; `\"flex\"` and explicit `\"priority\"` pass through as-is. Use `--service-tier default` to clear a configured tier for one run.\n\n## PDF inputs\n\n- When a PDF is provided and `--preprocess auto` is used, summarize sends the PDF as a file input via the OpenAI Responses API.\n- Document streaming is disabled for file inputs; non-streaming calls are used instead.\n\n<!-- File: .agents/skills/summarize/agents/openai.yaml (Tokens: ~52 | Category: anthropic-skill) -->\ninterface:\n  display_name: \"Summarize\"\n  short_description: \"Summarize URLs, files, and media with the CLI\"\n  default_prompt: \"Use $summarize to extract or summarize this URL, file, or media input.\"\n\n<!-- File: .agents/skills/summarize/SKILL.md (Tokens: ~1280 | Category: anthropic-skill) -->\n---\nname: summarize\ndescription: \"Summarize CLI: URLs, files, YouTube, transcripts, media, extraction, and JSON output.\"\n---\n\n# Summarize\n\nUse the `summarize` CLI as the canonical interface. Prefer a released binary on `PATH`; inside this repository, use `pnpm -s summarize` for the current checkout.\n\n## Start\n\n1. Confirm the command and current contract:\n\n   ```bash\n   summarize --version\n   summarize --help\n   ```\n\n2. Inspect model/provider readiness when a summary needs an LLM:\n\n   ```bash\n   summarize status\n   summarize status --json\n   ```\n\n3. Run the narrowest workflow below. Quote URLs and paths. Add `--timeout 2m` for slow remote or media inputs.\n\nNever print, request, or copy API-key values. `summarize status` reports availability without exposing secrets.\n\n## Summarize\n\nWeb page or remote document:\n\n```bash\nsummarize \"https://example.com/article\"\nsummarize \"https://example.com/report.pdf\" --length short\n```\n\nLocal file or stdin:\n\n```bash\nsummarize \"./report.pdf\"\nsummarize \"./recording.m4a\"\nprintf '%s\\n' \"Long text to summarize\" | summarize -\n```\n\nUse `--plain` for unrendered Markdown/text. Use `--language`, `--length`, `--prompt`, or `--prompt-file` only when the task requires an override. Use `--cli codex`, `--cli claude`, or another installed CLI provider when the user requests that provider or no direct API provider is configured.\n\n## Extract without a summary\n\nUse `--extract` to stop after extraction or transcription:\n\n```bash\nsummarize \"https://example.com/article\" --extract --format md\nsummarize \"./report.pdf\" --extract --format md\nsummarize \"https://youtu.be/VIDEO_ID\" --extract --format md\n```\n\n`--extract` does not support stdin. Extraction can still call configured transcription, OCR, Firecrawl, or Markdown services; it only skips the final summary call. `--markdown-mode llm` also invokes an LLM to reshape extracted text.\n\n## YouTube, audio, and video\n\nDefault transcript selection:\n\n```bash\nsummarize \"https://youtu.be/VIDEO_ID\"\nsummarize \"https://youtu.be/VIDEO_ID\" --extract --format md --timestamps\n```\n\nUse `--youtube web` to require web captions or `--youtube yt-dlp` to require the download/transcription path. Keep `auto` unless the user needs a specific source.\n\nLocal or remote audio/video:\n\n```bash\nsummarize \"./interview.mp3\" --extract\nsummarize \"./interview.mp4\" --extract --timestamps\nsummarize \"./interview.mp3\" --extract --diarize\n```\n\n`--transcriber auto` is the default. Use an explicit transcriber only when requested or diagnosing a provider. Diarization may require configured ElevenLabs or OpenAI access. Speaker identification is a separate opt-in step; do not infer identities without evidence.\n\nFor slides:\n\n```bash\nsummarize \"https://youtu.be/VIDEO_ID\" --slides\nsummarize \"./talk.mp4\" --slides --extract\n```\n\nSlide extraction may require `yt-dlp`; OCR requires `tesseract`.\n\n## JSON for automation\n\nUse JSON when another command or agent will parse the result:\n\n```bash\nsummarize \"https://example.com\" --json --metrics off > result.json\njq -r '.summary // .extracted.content // empty' result.json\n```\n\nThe stable top-level envelope contains `input`, `env`, `extracted`, `prompt`, `llm`, `metrics`, and `summary`. `summary` or `llm` can be `null` when extraction or a no-model path handles the input. In `--extract --json` mode, read extracted text from `.extracted.content`.\n\nJSON stays on stdout. Progress, warnings, and finish metrics stay on stderr. Do not merge stderr into stdout before parsing. Use `--metrics detailed` only when the task needs usage details.\n\n## Configuration and dependencies\n\nPrecedence: CLI flags, process environment, `~/.summarize/config.json`, built-in defaults. Prefer flags for one run; change config only when the user asks for a persistent default.\n\nUseful diagnostics:\n\n```bash\nsummarize status --verbose\nsummarize status --probe\nsummarize \"INPUT\" --verbose\n```\n\nPlain web summaries need no media tools. Media paths may use `ffmpeg`, `yt-dlp`, local Whisper/ONNX, or configured cloud transcription. Website fallback may use Firecrawl. Confirm the exact missing capability from the error before installing tools or changing config.\n\nInputs may be sent to the selected model, extraction, OCR, or transcription provider. For confidential material, confirm the approved provider or use an approved local path before running the command.\n\n## Verify\n\nAfter every run:\n\n- Require exit status `0`.\n- Require non-empty summary or extracted content.\n- For JSON, parse stdout with `jq` or another JSON parser.\n- For source-sensitive work, inspect `extracted`, `llm`, and stderr diagnostics rather than assuming the selected path.\n- Re-run the exact final command after changing provider, config, or flags.\n\nFor current option details, run `summarize --help` and read the repository documentation:\n\n- [Quickstart](../../../docs/quickstart.md)\n- [Main command](../../../docs/commands/summarize.md)\n- [Configuration](../../../docs/config.md)\n- [YouTube](../../../docs/youtube.md)\n- [Media](../../../docs/media.md)\n- [Extraction](../../../docs/extract-only.md)\n\n## Ownership\n\nThis file is the canonical agent workflow for the Summarize product. Keep generic agent workflows in `openclaw/agent-skills`; keep Summarize CLI behavior here. Downstream integrations should link to this file at a released tag or pinned commit and retain only their packaging or integration-specific notes. Do not maintain a second broad command guide downstream.\n\n<!-- File: docs/commands/daemon.md (Tokens: ~1096 | Category: command-prompt) -->\n---\ntitle: summarize daemon\npermalink: /docs/commands/daemon.html\nkicker: command\nsummary: \"Manage the local daemon and Chrome Native Messaging bridge used by the Side Panel.\"\n---\n\n# `summarize daemon`\n\n```text\nsummarize daemon <subcommand> [options]\n```\n\nManages the local HTTP daemon and its browser integration. The daemon binds to `127.0.0.1` only and requires a shared bearer token. Chrome reaches it through an optional exact-ID Native Messaging host; Firefox retains its existing loopback integration. The daemon autostarts via the right service manager for your platform.\n\n| Platform | Service               |\n| -------- | --------------------- |\n| macOS    | LaunchAgent (launchd) |\n| Linux    | systemd user service  |\n| Windows  | Scheduled Task        |\n\nIf you only use the CLI, you don't need any of this.\n\n## Subcommands\n\n### `install`\n\nInstall or upgrade the autostart service, write `~/.summarize/daemon.json`, and register Chrome native host `com.steipete.summarize` on macOS/Linux.\n\n```bash\nsummarize daemon install --token <TOKEN>\nsummarize daemon install --token <TOKEN> --port 8787\nsummarize daemon install --token <TOKEN> --dev --extension-id <UNPACKED_ID>\n```\n\n`--token <token>` is **required** on first install; the extension prints one after pairing. Re-running `install` with a new token adds another paired browser instead of invalidating the old one. The native host manifest allows only Chrome Web Store extension ID `cejgnmmhbbpdmjnfppjdfkocebngehfg`.\n\n### `restart`\n\nRestart the autostart service. Useful after upgrading summarize or editing `daemon.json`.\n\n```bash\nsummarize daemon restart\n```\n\n### `status`\n\nProbe the autostart service, Chrome native-host registration, and the running daemon's health endpoint.\n\n```bash\nsummarize daemon status\n```\n\n### `uninstall`\n\nUnload the autostart service and remove the user-level Chrome native host. On macOS the daemon plist is moved to Trash so you can undo.\n\n```bash\nsummarize daemon uninstall\n```\n\n### `run`\n\nRun the daemon in the foreground. The autostart entry uses this internally; use it directly inside containers, on systems without launchd/systemd, or while debugging.\n\n```bash\nsummarize daemon run --port 8787\n```\n\n## Options\n\n`--port <n>`\n: TCP port. Default `8787`. For a non-default port, set the same value in the extension under **Options → Runtime → Daemon → Port**. The native host reads `daemon.json` and rejects mismatched requests.\n\n`--token <token>`\n: Bearer token. Required for `install`; also accepted by `run`, which adds it alongside the stored tokens for that run (required when no `daemon.json` exists). Stored in `~/.summarize/daemon.json` (mode `0600`).\n\n`--dev`\n: Install a service that runs `src/cli.ts` via Node's native TypeScript support from the current repo. Useful while hacking on the daemon — don't ship it to users.\n\n`--extension-id <id>`\n: With `--dev`, bind the native host to an unpacked Chrome extension ID. Production installs always use the exact Web Store ID.\n\n## HTTP endpoints\n\nThe daemon is documented in detail in [Chrome extension](../chrome-extension.md) and [Agent / daemon](../agent.md). At a glance:\n\n- `POST /v1/summarize` — start a run. Bearer-auth required. Returns `{ ok, id }` JSON (`coalesced: true` when it joins an in-flight run for the same request).\n- `GET /v1/summarize/{id}/events` — SSE stream of progress events and the final result for a run.\n- `GET /health` — health probe (used by `status`).\n\n## Files\n\n`~/.summarize/daemon.json`\n: Bearer token(s), port, and an env snapshot captured at install (includes provider API keys). Mode `0600`.\n\n`~/.summarize/daemon.log`\n: Rolling log written by the autostart service.\n\n## Notes\n\n- **Containers** — `install` starts the daemon for the current container session but does not register a Scheduled Task / unit. Run `summarize daemon run` from your entrypoint. Do not expose the port as a Chrome Native Messaging substitute.\n- **Token rotation** — running `install --token <NEW>` adds a new paired browser; old browsers keep working. Edit `daemon.json` by hand to revoke.\n- **Multiple installs** — only one daemon per user. Reinstall to upgrade; omitting `--port` preserves the configured port.\n- **Windows** — the npm-installed CLI still needs a packaged native-host `.exe`; do not route daemon traffic through the Direct-provider loopback grants as a workaround. Direct and Browser modes continue to work.\n\n## See also\n\n- [Chrome extension](../chrome-extension.md) — pairing flow + Side Panel UI.\n- [Agent / daemon](../agent.md) — automation surface.\n\n<!-- File: docs/commands/index.md (Tokens: ~899 | Category: command-prompt) -->\n---\ntitle: Commands\npermalink: /docs/commands/\nkicker: reference\nsummary: \"Every summarize subcommand and flag, with examples.\"\n---\n\n# Command reference\n\n`summarize` is one binary with a handful of subcommands. The default subcommand is `summarize` itself — the one you use 99% of the time. The others wrap related tooling.\n\n## Subcommands\n\n- [`summarize`](summarize.md) — main command. Takes a URL, file, or stdin and produces a summary or extracted content.\n- [`summarize status`](../cli.md#cli-discovery) — print the selected model, enabled providers, and runtime status.\n- [`summarize slides`](slides.md) — extract scene-change keyframes from a YouTube URL, direct video URL, or local video file into PNGs (and optional OCR text). Standalone version of the `--slides` flag.\n- [`summarize transcriber`](transcriber.md) — set up local ONNX transcription (Parakeet, Canary). Prints the env vars you need.\n- [`summarize daemon`](daemon.md) — manage the local HTTP daemon that the Chrome Side Panel talks to. Subcommands: `install`, `restart`, `status`, `uninstall`, `run`.\n- [`summarize refresh-free`](refresh-free.md) — scan OpenRouter `:free` models, write working candidates to `~/.summarize/config.json`.\n- `summarize help [topic]` — print help for the CLI or a subcommand (`slides`, `status`, `daemon`, `transcriber`, `refresh-free`).\n\n## Output discipline\n\nAll subcommands keep the same output discipline — straight from gogcli's playbook so pipes and scripts stay parseable:\n\n- **stdout:** the result. Plain text, Markdown, JSON, or files (slides only).\n- **stderr:** progress, prompts, warnings, and errors.\n- `--json` produces a stable envelope on stdout.\n- `--no-color` strips ANSI; `--plain` skips ANSI/OSC rendering for Markdown.\n\n## Global behavior\n\nOnly two flags apply to every subcommand; the rest are per-command:\n\n| Flag                          | Where it works                                                                                                                             |\n| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |\n| `--locale <locale>`           | Everywhere. Interface language: `auto` plus the shipped UI locales (`SUMMARIZE_LOCALE` too).                                               |\n| `--help`                      | Everywhere (`summarize help <topic>` prints topic help).                                                                                   |\n| `-V`, `--version`             | `summarize`, `summarize slides`.                                                                                                           |\n| `--json`                      | `summarize`, `summarize slides`, `summarize status`.                                                                                       |\n| `--no-color`                  | `summarize`, `summarize status`, `summarize refresh-free`, `summarize transcriber`.                                                        |\n| `--theme <name>`              | `summarize`, `summarize slides`, `summarize transcriber` (`SUMMARIZE_THEME` env var also works).                                           |\n| `--verbose` / `--debug`       | `summarize`, `summarize slides`, `summarize refresh-free`, `summarize daemon`, `summarize transcriber`. `status` accepts `--verbose` only. |\n| `--metrics off\\|on\\|detailed` | `summarize` only.                                                                                                                          |\n| `--timeout <duration>`        | `summarize`, `summarize slides`.                                                                                                           |\n\n## Exit codes\n\n| Code  | Meaning                                                                     |\n| ----- | --------------------------------------------------------------------------- |\n| `0`   | Success.                                                                    |\n| `1`   | Any failure — usage errors, extraction, model, network, and timeouts alike. |\n| `130` | Interrupted by SIGINT (Ctrl+C).                                             |\n| `143` | Terminated by SIGTERM.                                                      |\n\n`summarize daemon` and `summarize transcriber` still exit `1` when the underlying service install (launchd, systemd, schtasks) fails; the platform's own error text is included in the message — check `--verbose` output for the raw error.\n\n<!-- File: docs/commands/refresh-free.md (Tokens: ~839 | Category: command-prompt) -->\n---\ntitle: summarize refresh-free\npermalink: /docs/commands/refresh-free.html\nkicker: command\nsummary: \"Scan OpenRouter :free models and write working candidates to config.\"\n---\n\n# `summarize refresh-free`\n\n```text\nsummarize refresh-free [--runs 2] [--smart 3] [--min-params 27b]\n                       [--max-age-days 180] [--set-default] [--verbose]\n```\n\nProbes [OpenRouter](https://openrouter.ai)'s catalog for `:free` models, runs them on a small benchmark, and writes the working ones to `models.free` in `~/.summarize/config.json`. Useful when you want to use `--model free` without picking a specific OpenRouter slug.\n\nNeeds `OPENROUTER_API_KEY` in the environment.\n\n## What it does\n\n1. Pulls the OpenRouter model catalog.\n2. Filters to models tagged `:free` that meet `--min-params` and `--max-age-days`.\n3. Benchmarks every candidate once against a sanity prompt, then probes the shortlisted candidates `--runs` more times; ranks by `--smart` heuristics (latency, completion length, refusal rate).\n4. Writes the survivors to `models.free` in `~/.summarize/config.json`.\n5. With `--set-default`, also sets top-level `model` to `free`.\n\nAfter the run, `summarize \"https://example.com\" --model free` rotates through the saved list until one succeeds.\n\n## Flags\n\n`--runs <n>`\n: Extra refinement probes per shortlisted candidate after the initial benchmark run (`1 + --runs` total). `0` skips refinement. Default `2`.\n\n`--smart <n>`\n: How many top candidates to keep. Default `3`.\n\n`--min-params <size>`\n: Minimum parameter count. Accepts `7b`, `27b`, `70b`, etc. Default `27b`.\n\n`--max-age-days <n>`\n: Reject models older than N days based on OpenRouter's metadata. Default `180`.\n\n`--set-default`\n: Also set `model: \"free\"` at the top level of `~/.summarize/config.json`.\n\n`--verbose` / `--debug`\n: Per-candidate progress, timings, and rejection reasons on stderr.\n\n## Examples\n\n```bash\n# Quick refresh; keep the best 3 free models ≥27B, ≤180d old.\nsummarize refresh-free\n\n# Looser filter — accept smaller / older models.\nsummarize refresh-free --min-params 7b --max-age-days 365\n\n# Refresh and also set the default model.\nsummarize refresh-free --set-default\n\n# Verbose ranking output for debugging.\nsummarize refresh-free --runs 3 --smart 5 --verbose\n```\n\n## Output\n\n`~/.summarize/config.json` is updated in place. The relevant section ends up looking like:\n\n```json\n{\n  \"models\": {\n    \"free\": [\"openai/gpt-oss-120b:free\", \"z-ai/glm-4.6:free\", \"deepseek/deepseek-r1:free\"]\n  }\n}\n```\n\nA short summary of survivors and rejected candidates is printed on stderr. The only stdout line is the localized config-write confirmation, e.g. `Wrote /Users/you/.summarize/config.json (models.free)` — a sentence containing the path, not a bare path value.\n\nColor follows the rest of the CLI: `FORCE_COLOR=0` disables it, while a nonzero `FORCE_COLOR` takes precedence over `NO_COLOR`. Without an override, color requires a capable terminal.\n\n## See also\n\n- [LLM overview](../llm.md) — `--model` syntax, including `free`.\n- [Auto selection](../model-auto.md) — how `auto` picks across providers.\n- [Config](../config.md) — full schema for `~/.summarize/config.json`.\n\n<!-- File: docs/commands/slides.md (Tokens: ~1085 | Category: command-prompt) -->\n---\ntitle: summarize slides\npermalink: /docs/commands/slides.html\nkicker: command\nsummary: \"Extract scene-change keyframes from a video source into PNG files.\"\n---\n\n# `summarize slides`\n\n```text\nsummarize slides <source> [flags]\n```\n\nExtracts slide-shaped keyframes from a YouTube URL, direct video URL, or local video file using FFmpeg scene detection. Native ffmpeg is preferred; bundled FFmpeg WebAssembly is used when native `ffmpeg`/`ffprobe` are unavailable. Output is a directory of PNGs (and optional OCR text). This is the standalone form of the `--slides` flag on the main command — useful when you only want the slides without a summary.\n\n## Synopsis\n\n```bash\nsummarize slides \"https://youtu.be/...\"\nsummarize slides \"https://youtu.be/...\" --render auto\nsummarize slides \"https://youtu.be/...\" --slides-ocr -o ./out\nsummarize slides \"https://example.com/lecture.mp4\" --slides-max 12\nsummarize slides ./lecture.mp4 --slides-max 12\n```\n\n## Requirements\n\n- Bundled FFmpeg WebAssembly, or native `ffmpeg` on PATH for faster extraction and broader codec support.\n- `yt-dlp` on PATH for YouTube URLs.\n- `tesseract` on PATH for `--slides-ocr`.\n\nIf a required tool is missing, summarize prints a clear warning and exits non-zero.\n\n## Flags\n\n`--slides-ocr`\n: Run OCR on every extracted slide. Stores `ocrText` and `ocrConfidence` in `slides.json` and the JSON response.\n\n`--slides-dir <dir>`\n: Output base directory. Default: `./slides`. A per-video subfolder is created inside.\n\n`-o, --output <dir>`\n: Alias for `--slides-dir`.\n\n`--slides-scene-threshold <value>`\n: Scene detection threshold, `0.1`–`1.0`. Default `0.3`. Lower values detect more scenes (more slides); higher values are stricter.\n\n`--slides-max <count>`\n: Cap on extracted slides. Default `6`.\n\n`--slides-min-duration <seconds>`\n: Minimum gap between slides. Default `2`.\n\n`--render <mode>`\n: Inline render of thumbnails: `auto`, `kitty`, `iterm`, `none`. Default `none` — paths are printed instead.\n\n`--theme <name>`\n: Pick a CLI theme.\n\n`--timeout <duration>`\n: Per-operation timeout setting. Default `2m`; not an overall wall-clock deadline. yt-dlp downloads and FFmpeg scene detection allow at least `5m`, and individual extraction/probe steps have their own limits.\n\n`--no-cache`\n: Force re-download and re-extraction (bypasses both caches).\n\n`--json`\n: JSON envelope on stdout. Disables inline rendering.\n\n`--verbose` / `--debug`\n: Detailed progress on stderr.\n\n`-V`, `--version`\n: Print version and exit.\n\n## Output\n\nEach run writes a directory like:\n\n```text\nslides/<source-id>/\n  slide_0001_18.60s.png\n  slide_0002_42.20s.png\n  ...\n  slides.json\n```\n\nThe filenames include the slide index and timestamp. `slides.json` records the manifest, including OCR results when requested; OCR does not create separate text files. `ocrConfidence` uses a 0–1 scale.\n\nIn `--json` mode, stdout contains an envelope like this (additional extraction metadata omitted):\n\n```json\n{\n  \"ok\": true,\n  \"slides\": {\n    \"sourceUrl\": \"https://example.com/lecture.mp4\",\n    \"slidesDir\": \"/absolute/path/slides/<id>\",\n    \"slides\": [\n      {\n        \"index\": 1,\n        \"timestamp\": 18.6,\n        \"imagePath\": \"/absolute/path/slides/<id>/slide_0001_18.60s.png\",\n        \"ocrText\": \"Recognized slide text\",\n        \"ocrConfidence\": 0.92\n      }\n    ]\n  }\n}\n```\n\n## Inline rendering\n\n`--render auto` detects Kitty (`KITTY_WINDOW_ID`) and iTerm (`TERM_PROGRAM=iTerm.app`) and uses the matching image protocol. On unsupported terminals, slides are listed by path instead.\n\n## Examples\n\n```bash\n# Quick preview in iTerm/Kitty.\nsummarize slides \"https://youtu.be/...\" --render auto\n\n# Big lecture, more granular cuts.\nsummarize slides \"https://youtu.be/...\" \\\n  --slides-max 24 --slides-scene-threshold 0.2\n\n# Pipe-friendly JSON for an automation.\nsummarize slides \"https://youtu.be/...\" --json | jq '.slides.slides[].imagePath'\n\n# Force re-extraction after editing the source video.\nsummarize slides \"./talk.mp4\" --no-cache -o ./out\n```\n\n## See also\n\n- [Slides mode](../slides.md) — the inline `--slides` flag on the main command.\n- [Slides rendering flow](../slides-rendering-flow.md) — pipeline internals.\n\n<!-- File: docs/commands/summarize.md (Tokens: ~2802 | Category: command-prompt) -->\n---\ntitle: summarize\npermalink: /docs/commands/summarize.html\nkicker: command\nsummary: \"Main command. URL, file, or stdin → clean text → summary.\"\n---\n\n# `summarize`\n\n```text\nsummarize [input] [flags]\n```\n\nTakes a URL, local file path, or `-` for stdin and produces a summary. With `--extract`, prints cleaned content instead of summarizing; stdin is not supported in extract mode.\n\n## Synopsis\n\n```bash\nsummarize \"https://example.com/article\"\nsummarize ./report.pdf --model openai/gpt-5-mini\nsummarize \"https://youtu.be/...\" --slides --slides-ocr\npbpaste | summarize -\nsummarize \"https://example.com\" --extract --format md > clean.md\nsummarize \"https://example.com\" --json --metrics detailed\n```\n\n## Input\n\n- **URL** — http/https. YouTube, podcast hosts, generic articles, raw media.\n- **File path** — PDF, image, audio, video, plain text, Markdown, HTML.\n- **`-`** — read content from stdin (text or binary).\n\nIf `[input]` is omitted, summarize prints concise help and exits.\n\n## Flags\n\n### Extraction\n\n`--extract`\n: Print extracted content and exit. No LLM call. Supports URLs, YouTube/direct media, local audio/video, and local PDFs; `-` stdin is not supported. The `--extract-only` alias is hidden but still works.\n: Extraction can still use configured remote transcription, OCR, or Markdown providers for media/PDF inputs.\n\n`--format <format>`\n: `md`/`markdown` or `text`/`txt`/`plain`. Controls website extraction format and whether files are preprocessed to Markdown for model compatibility. Default: `text`. Default in `--extract` mode for URLs: `md`.\n\n`--firecrawl <mode>`\n: `off`, `auto`, `always`. `auto` falls back to Firecrawl when local extraction looks blocked or thin. Needs `FIRECRAWL_API_KEY`.\n\n`--preprocess <mode>`\n: `off`, `auto`, `always`. Default `auto`. Controls `markitdown` usage for files. `always` only affects file inputs.\n: Image-only PDFs can retry through OpenAI vision OCR when `OPENAI_API_KEY` is set. Set `MARKITDOWN_OCR_MODEL` to choose the OCR model, or `MARKITDOWN_OCR_DPI` to tune rendered page size.\n\n`--markdown-mode <mode>`\n: `off`, `auto`, `llm`, `readability`. For websites: HTML → Markdown strategy. For YouTube/transcripts: `llm` formats raw transcripts into clean Markdown with headings. The `--markdown` alias is hidden and deprecated.\n\n`--max-extract-characters <count>`\n: Cap printed characters in `--extract` mode. Default: unlimited.\n\n### YouTube / video\n\n`--youtube <mode>`\n: `auto`, `web`, `apify`, `yt-dlp`, `no-auto` (skip auto-generated captions). Default `auto`.\n\n`--transcriber <name>`\n: Select the local transcription stage: `auto`, `whisper`, `parakeet`, `canary`. Default `auto` — Groq still runs first when keyed, then local ONNX/`whisper.cpp`, then cloud fallbacks.\n\n`--video-mode <mode>`\n: `auto`, `transcript`, `understand`. `understand` prefers vision/video understanding when supported.\n\n`--embedded-video <mode>`\n: `auto`, `off`, `prefer`, `both`. Controls embedded YouTube handling on regular web pages: `off` keeps the article text only, `prefer` favors the video transcript, `both` combines labeled article + transcript sections. Default `auto` — uses only high-confidence primary embeds. See [Website mode](../website.md).\n\n`--timestamps`\n: Include timestamps in transcripts when available.\n\n`--diarize [provider]`\n: Add speaker labels to YouTube, local audio/video, or direct media URLs. Provider: `auto`, `elevenlabs`, or `openai`.\n\n`--identify-speakers` / `--no-identify-speakers`\n: Resolve generic diarization labels to names, or disable configured resolution for one run. Uses authoritative anchors and OpenAI GPT-5.5 context inference.\n\n`--speaker-profile <name>`\n: Select a reusable profile from `speakers.profiles` in the config file.\n\n`--speaker-at <timestamp=name>`\n: Name the speaker active at a timestamp. Repeat the flag for multiple speakers.\n\n`--remember-speakers`\n: Atomically persist resolved names, anchors, and a transcript-hash-guarded source mapping under the selected profile.\n\n### Slides\n\n`--slides [on|off]` / `--no-slides`\n: Extract slides from a YouTube URL, direct video URL, or local video file and render inline alongside the summary. Combine with `--extract` to interleave slides in the full transcript. See [Slides mode](../slides.md).\n: The optional value accepts boolean words (`on`/`off`, `true`/`false`, `yes`/`no`, `1`/`0`); anything else is rejected. Use `--no-slides` to disable slide extraction enabled in the config file for one run.\n\n`--slides-ocr` / `--no-slides-ocr`\n: Run OCR on extracted slides. Requires `tesseract`.\n: Use `--no-slides-ocr` to disable configured slide OCR while retaining slide extraction.\n\n`--slides-debug`\n: Print slide image paths instead of rendering inline (useful in non-image terminals).\n\n`--slides-dir <dir>`\n: Output directory base. Default `./slides`.\n\n`--slides-scene-threshold <value>`\n: Scene detection threshold, `0.1`–`1.0`. Default `0.3`.\n\n`--slides-max <count>`\n: Cap on extracted slides. Default `6`.\n\n`--slides-min-duration <seconds>`\n: Minimum gap between slides. Default `2`.\n\n### Summary control\n\n`--length <length>`\n: `short`, `medium`, `long`, `xl`, `xxl` (or `s`/`m`/`l`) or a character cap like `20000` or `20k`. Default `long`. Override globally via `output.length` in [Config](../config.md).\n\n`--force-summary`\n: Always run the LLM, even when extracted content is shorter than the requested length.\n\n`--language, --lang <language>`\n: `auto`, `en`, `de`, `english`, `german`, … Default `auto` (matches source). Configurable via `output.language`.\n\n`--locale <locale>`\n: CLI interface language: `auto` plus the shipped UI locales (`en`, `de`, `fr`, `es`, `it`, `pt-BR`, `nl`, `pl`, `ru`, `ja`, `zh-Hans`, `zh-Hant`, `ko`, `tr`). Default follows the system locale with English fallback. `SUMMARIZE_LOCALE` also works. See [Localization](../localization.md).\n\n`--prompt <text>` / `--prompt-file <path>`\n: Override the summary prompt. Content is appended after the override.\n\n### Models\n\n`--model <model>`\n: Model id. `auto`, `<config-preset>`, `cli/<provider>/<model>`, `xai/...`, `openai/...`, `nvidia/...`, `minimax/...`, `google/...`, `anthropic/...`, `zai/...`, `ollama/<model>` (local Ollama), `openclaw/<model>` (shorthand for `cli/openclaw/<model>`), or `openrouter/<author>/<slug>`. Default `auto`. See [LLM overview](../llm.md).\n\n`--cli [provider]`\n: Use a logged-in CLI provider: `claude`, `gemini`, `codex`, `agent`, `openclaw`, `opencode`, `copilot`, `agy`, `pi`, `devin`, `grok`. Equivalent to `--model cli/<provider>`. Without a value: enable CLI providers in auto-selection.\n\n`--thinking <effort>`\n: Reasoning effort. `none`, `low`, `medium`, `high`, `xhigh`, `max` (GPT-6 models). Aliases: `off`, `min`, `med`, `mid`, `x-high`, `extra-high`. Affects reasoning-capable models on the dispatched provider (OpenAI, Anthropic Claude 4+, pi CLI).\n\n`--service-tier <tier>`\n: OpenAI service tier. `default`, `fast`, `priority`, `flex`. Maps to `service_tier` on the request.\n\n`--fast`\n: Shortcut for OpenAI `service_tier=priority`. Same effect as `--service-tier fast`.\n\n`--max-output-tokens <count>`\n: Hard cap for LLM output tokens. Accepts `2000`, `2k`. Overrides provider defaults.\n\n`--retries <count>`\n: LLM retry attempts after timeouts or transient API failures. `0`–`5`. Default `1`.\n\n### Output\n\n`--json`\n: Structured JSON envelope on stdout. Includes prompt + metrics. Disables streaming.\n\n`--stream <mode>`\n: `auto`, `on`, `off`. Default `auto` (TTY-only). Disabled in `--json` mode.\n\n`--plain`\n: Keep raw text/Markdown — no ANSI/OSC rendering.\n\n`--no-color`\n: Disable ANSI colors.\n\n`--width <columns>`\n: Override terminal width for Markdown rendering. Default: auto-detect, max 120.\n\n`--theme <name>`\n: Pick a CLI theme. Run `summarize --help` for the list. Env: `SUMMARIZE_THEME`.\n\n### Cache\n\n`--no-cache`\n: Bypass the summary (LLM) cache. Media + transcript caches stay enabled.\n\n`--no-media-cache`\n: Disable the media download cache (`yt-dlp` outputs).\n\n`--cache-stats`\n: Print cache stats and exit.\n\n`--clear-cache`\n: Delete the cache database and exit.\n\nSee [Cache internals](../cache.md) for what's cached and where.\n\n### Diagnostics\n\n`--verbose`\n: Detailed progress on stderr.\n\n`--debug`\n: Alias for `--verbose`. Also defaults `--metrics` to `detailed`.\n\n`--metrics <mode>`\n: `off`, `on`, `detailed`. Default `on`. Adds a compact second-line breakdown on stderr when `detailed`.\n\n`--timeout <duration>`\n: Per-operation timeout for content fetching and LLM requests (not an overall wall-clock deadline). `30`, `30s`, `2m`, `5000ms`. Default `2m`.\n\n`-V`, `--version`\n: Print version and exit.\n\n## Examples\n\n```bash\n# Extracted plain text from a URL.\nsummarize \"https://example.com\" --extract\n\n# Extracted Markdown — prefers Firecrawl when configured.\nsummarize \"https://example.com\" --extract --format md\n\n# YouTube transcript as cleanly-formatted Markdown.\nsummarize \"https://www.youtube.com/watch?v=...\" \\\n  --extract --format md --markdown-mode llm\n\n# ElevenLabs diarization with verified speaker names.\nsummarize \"https://www.youtube.com/watch?v=...\" --extract \\\n  --diarize elevenlabs --identify-speakers \\\n  --speaker-profile my-podcast --speaker-at \"0:12=Host Name\" --remember-speakers\n\n# Inline slides + summary.\nsummarize \"https://www.youtube.com/watch?v=...\" --slides\n\n# Full transcript + inline slides.\nsummarize \"https://www.youtube.com/watch?v=...\" --slides --extract\n\n# Hard caps + a specific model.\nsummarize \"https://example.com\" \\\n  --length 20k --max-output-tokens 2k --timeout 2m \\\n  --model openai/gpt-5-mini\n\n# OpenAI fast tier with reasoning.\nsummarize \"https://example.com\" \\\n  --model openai/gpt-5.5 --fast --thinking medium\n\n# Config preset (alias defined in ~/.summarize/config.json).\nsummarize \"https://example.com\" --model mymodel\n\n# Strict JSON for scripts.\nsummarize \"https://example.com\" --json --verbose\n\n# Summarize the clipboard.\npbpaste | summarize -\n```\n\n## Environment\n\nThe provider keys and binary paths picked up at runtime are listed in [LLM overview](../llm.md#env). `SUMMARIZE_MODEL` overrides the default model selection; `SUMMARIZE_THEME` picks the theme; `SUMMARIZE_LOCALE` picks the interface language.\n\n## See also\n\n- [LLM overview](../llm.md) — how `--model` resolves to a provider.\n- [Website mode](../website.md), [YouTube](../youtube.md), [Media + podcasts](../media.md).\n- [Cache](../cache.md), [Firecrawl](../firecrawl.md).\n- [Config](../config.md) for persistent defaults.\n\n<!-- File: docs/commands/transcriber.md (Tokens: ~618 | Category: command-prompt) -->\n---\ntitle: summarize transcriber\npermalink: /docs/commands/transcriber.html\nkicker: command\nsummary: \"Set up local ONNX transcription (Parakeet, Canary).\"\n---\n\n# `summarize transcriber`\n\n```text\nsummarize transcriber setup [--model parakeet|canary] [--theme <name>]\n```\n\nConfigures local ONNX transcription. The command **prints the env vars** you need to export — it doesn't write to your shell config. Once those vars are exported, `--transcriber auto` (or `SUMMARIZE_TRANSCRIBER=auto`) uses ONNX after Groq and before `whisper.cpp` and the remaining cloud fallbacks.\n\n## How auto picks a transcriber\n\nWhen `--transcriber auto` is set (default), summarize tries providers in this order:\n\n1. **Groq** — fastest cloud option. Needs `GROQ_API_KEY`.\n2. **Local ONNX** (Parakeet or Canary), then `whisper.cpp` — fully offline. ONNX needs the env vars from this command.\n3. **AssemblyAI / Gemini / OpenAI / FAL / Deepgram** — cloud fallbacks, in that order, gated by their respective API keys.\n\n`OPENAI_WHISPER_BASE_URL` changes the endpoint used by the OpenAI transcription stage; it is not a separate provider in the order above.\n\n## Subcommand\n\n### `summarize transcriber setup`\n\n`--model <name>`\n: `parakeet` (default) or `canary`. Picks which ONNX model the printed snippet targets.\n\n`--theme <name>`\n: CLI theme override.\n\nThe output is a labelled, copy-pasteable block of `export` lines for your shell. Re-run with the other model to switch.\n\n## Environment\n\nSet by the printed snippet:\n\n`SUMMARIZE_ONNX_PARAKEET_CMD`\n: Command to run Parakeet ONNX transcription. Use `{input}` as the audio-file placeholder.\n\n`SUMMARIZE_ONNX_CANARY_CMD`\n: Command to run Canary ONNX transcription. Use `{input}` as the audio-file placeholder.\n\n`SUMMARIZE_TRANSCRIBER`\n: Optional. Select the local stage with `auto`, `whisper`, `parakeet`, or `canary` without passing `--transcriber` every time.\n\n## Examples\n\n```bash\n# Default: Parakeet.\nsummarize transcriber setup\n\n# Set up Canary instead.\nsummarize transcriber setup --model canary\n\n# After exporting the printed vars:\nsummarize \"https://podcasts.apple.com/.../episode-...\" --transcriber parakeet\n```\n\n## See also\n\n- [ONNX transcription](../nvidia-onnx-transcription.md) — how to actually install the model + runtime.\n- [Transcript provider flow](../transcript-provider-flow.md) — full selection waterfall.\n\n<!-- File: packages/core/README.md (Tokens: ~271 | Category: plugin-manifest) -->\n# @steipete/summarize-core\n\nCore library for Summarize (content extraction + prompt builders).\n\n- CLI package: `@steipete/summarize`\n- Recommended imports (library use): `@steipete/summarize-core/content`, `@steipete/summarize-core/prompts`\n\nThe content entry point also exports DNS-pinned network helpers. `fetchWithDnsPinnedAddresses` accepts addresses attached with `attachDnsPinnedAddresses`; callers must validate those addresses first or use `createNetworkGuardedFetch` for validation. The transport honors cancellation from either a `Request` or its init options, returns null bodies for HEAD and HTTP 204/205/304, and rejects invalid HTTP responses through its promise.\n\nThe network guard revalidates every followed redirect and cancels discarded redirect bodies. Same-origin redirects retain request options and credentials; origin changes strip explicit authorization and cookie headers, including changes of scheme or port. Manual redirects remain available for the caller to consume.\n\nThe `@steipete/summarize-core/processes` entry point provides `signalTrackedProcess(child, signal)` for stopping one tracked command and its process tree, alongside `terminateTrackedProcesses(signal)` for all tracked commands. Use the per-command helper for deadlines so sibling work continues.\n</yakaai_skills>"}