Fast summaries from URLs, files, and media. Works in the terminal, a Chrome Side Panel and Firefox Sidebar.
- Chrome Side Panel chat (streaming agent + history) inside the sidebar.
- Video slides: screenshots + OCR + transcript cards for YouTube, direct video URLs, and local video files.
- Media-aware summaries: auto‑detect video/audio vs page content.
- Coding CLI backends: Codex, Claude, Gemini, Cursor Agent, OpenClaw, OpenCode.
- Streaming Markdown + metrics + cache‑aware status.
- CLI supports URLs, files, podcasts, YouTube, audio/video, PDFs.
- URLs, files, and media: web pages, PDFs, images, audio/video, YouTube, podcasts, RSS.
- Slide extraction for video sources (YouTube, direct video URLs, local video files) with OCR + timestamped cards.
- Transcript-first media flow: published transcripts when available, then Groq/ONNX/whisper.cpp/AssemblyAI/Gemini/OpenAI/FAL transcription fallback when not.
- Coding CLI providers: Claude, Codex, Gemini, Cursor Agent, OpenClaw, OpenCode, GitHub Copilot, Antigravity, pi.
- Streaming output with Markdown rendering, metrics, and cache-aware status.
- Local, paid, and free models: OpenAI‑compatible local endpoints, paid providers, plus an OpenRouter free preset.
- Output modes: Markdown/text, JSON diagnostics, extract-only, metrics, timing, and cost estimates.
- Smart default: if content is shorter than the requested length, we return it as-is (use
--force-summaryto override).
One‑click summarizer for the current tab. Chrome Side Panel + Firefox Sidebar + local daemon for streaming Markdown.
Chrome Web Store: Summarize Side Panel
YouTube slide screenshots (from the browser):
- Install the CLI (choose one):
- npm (cross‑platform):
npm i -g @steipete/summarize - Homebrew (Homebrew/core):
brew install summarize
- npm (cross‑platform):
- Install the extension (Chrome Web Store link above) and open the Side Panel.
- The panel shows a token + install command. Run it in Terminal:
summarize daemon install --token <TOKEN>
Why a daemon/service?
- Browser mode works without the daemon for page summaries, ranged video slides through MediaBunny/WebCodecs, and fetchable YouTube/direct/embedded media transcription with browser-cached Whisper.
- The optional daemon on
127.0.0.1is faster and adds native ffmpeg, configurable transcription providers, OCR, and broader media support. - The service autostarts (launchd/systemd/Scheduled Task) so the Side Panel is always ready.
If you only want the CLI, you can skip the daemon install entirely.
Notes:
- Summarization only runs when the Side Panel is open.
- Auto mode summarizes on navigation (incl. SPAs); otherwise use the button.
- Daemon is localhost-only and requires a shared token; rerunning
summarize daemon install --token <TOKEN>adds another paired browser token instead of invalidating the old one. - Autostart: macOS (launchd), Linux (systemd user), Windows (Scheduled Task).
- Windows containers:
summarize daemon installstarts the daemon for the current container session but does not register a Scheduled Task. Run it each time the container starts or add that command to your container startup, and publish port8787so the host browser can reach the daemon. - Tip: configure
freeviasummarize refresh-free(needsOPENROUTER_API_KEY). Add--set-defaultto set model=free.
More:
- Step-by-step install: apps/chrome-extension/README.md
- Architecture + troubleshooting: docs/chrome-extension.md
- Firefox compatibility notes: apps/chrome-extension/docs/firefox.md
- Select Video + Slides in the Summarize picker.
- Slides render at the top; expand to full‑width cards with timestamps.
- Click a slide to seek the video; toggle Transcript/OCR when OCR is significant.
- Browser mode uses MediaBunny with native WebCodecs and ranged network reads for fetchable videos, then falls back to visible-tab capture when the source or codec is unavailable.
- Daemon mode adds
yt-dlp, native ffmpeg, and optionaltesseractOCR.
- Build + load the extension (unpacked):
- Chrome:
pnpm -C apps/chrome-extension buildchrome://extensions→ Developer mode → Load unpacked- Pick:
apps/chrome-extension/.output/chrome-mv3
- Firefox:
pnpm -C apps/chrome-extension build:firefoxabout:debugging#/runtime/this-firefox→ Load Temporary Add-on- Pick:
apps/chrome-extension/.output/firefox-mv3/manifest.json
- Chrome:
- Open Side Panel/Sidebar → copy token.
- Install daemon in dev mode:
pnpm summarize daemon install --token <TOKEN> --dev
Requires Node 24+.
- npx (no install):
npx -y @steipete/summarize "https://example.com"- npm (global):
npm i -g @steipete/summarize- npm (library / minimal deps):
npm i @steipete/summarize-coreimport { createLinkPreviewClient } from "@steipete/summarize-core/content";- Homebrew:
brew install summarizeHomebrew ships from homebrew/core via brew install summarize.
If Homebrew is unavailable in your environment, use the npm global install above.
Install these if you want media-heavy features:
ffmpeg: optional native accelerator with broader codec support; bundled WebAssembly is the fallbackyt-dlp: required for YouTube slide extraction and some remote media flowstesseract: optional OCR for--slides-ocr- Optional cloud transcription providers:
GROQ_API_KEYASSEMBLYAI_API_KEYELEVENLABS_API_KEY(speaker diarization)GEMINI_API_KEY/GOOGLE_GENERATIVE_AI_API_KEY/GOOGLE_API_KEYOPENAI_API_KEYFAL_KEY
macOS (Homebrew):
brew install ffmpeg yt-dlp
brew install tesseract # optional, for --slides-ocrIf native ffmpeg/ffprobe are unavailable, Summarize uses the bundled WebAssembly build. Native ffmpeg remains recommended for speed and broader codec/filter support.
- CLI only: just install via npm/Homebrew and run
summarize ...(no daemon needed). - Chrome extension: Browser mode works without the CLI or daemon; install the daemon for faster and broader media support.
- Firefox extension: install the CLI and daemon for media extraction.
summarize "https://example.com"Inspect the effective model setup. Status only lists configured or usable providers; it never prints keys or missing-provider noise.
summarize status
summarize status --verbose
summarize status --probe
summarize status --json--probe checks supported model-list endpoints without running paid inference. CLI providers are
reported as available when their enabled executable is present; API providers are reported as
configured when an effective key is present.
URLs or local paths:
summarize "/path/to/file.pdf" --model google/gemini-3-flash
summarize "https://example.com/report.pdf" --model google/gemini-3-flash
summarize "/path/to/audio.mp3"
summarize "/path/to/video.mp4"Stdin (pipe content using -):
echo "content" | summarize -
pbpaste | summarize -
# binary stdin also works (PDF/image/audio/video bytes)
cat /path/to/file.pdf | summarize -Notes:
- Stdin has a 50MB size limit
- The
-argument tells summarize to read from standard input - Text stdin is treated as UTF-8 text (whitespace-only input is rejected as empty)
- Binary stdin is preserved as raw bytes and file type is auto-detected when possible
- Useful for piping clipboard content or command output
YouTube (supports youtube.com and youtu.be):
summarize "https://youtu.be/dQw4w9WgXcQ" --youtube autoPodcast RSS (transcribes latest enclosure):
summarize "https://feeds.npr.org/500005/podcast.xml"Apple Podcasts episode page:
summarize "https://podcasts.apple.com/us/podcast/2424-jelly-roll/id360084272?i=1000740717432"Spotify episode page (best-effort; may fail for exclusives):
summarize "https://open.spotify.com/episode/5auotqWAXhhKyb9ymCuBJY"HLS playlist:
summarize "https://example.com/master.m3u8"--length controls how much output we ask for (guideline), not a hard cap.
The built-in default is long.
Set a default in ~/.summarize/config.json with output.length.
summarize "https://example.com" --length long
summarize "https://example.com" --length 20k- Presets:
short|medium|long|xl|xxl - Character targets:
1500,20k,20000 - Optional hard cap:
--max-output-tokens <count>(e.g.2000,2k)- Provider/model APIs still enforce their own maximum output limits.
- If omitted, no max token parameter is sent (provider default).
- Prefer
--lengthunless you need a hard cap.
- Short content: when extracted content is shorter than the requested length, the CLI returns the content as-is.
- Override with
--force-summaryto always run the LLM.
- Override with
- Minimums:
--lengthnumeric values must be >= 10 chars;--max-output-tokensmust be >= 16. - Preset targets (source of truth:
packages/core/src/prompts/summary-lengths.ts):- short: target ~900 chars (range 600-1,200)
- medium: target ~1,800 chars (range 1,200-2,500)
- long: target ~4,200 chars (range 2,500-6,000)
- xl: target ~9,000 chars (range 6,000-14,000)
- xxl: target ~17,000 chars (range 14,000-22,000)
Best effort and provider-dependent. These usually work well:
text/*and common structured text (.txt,.md,.json,.yaml,.xml, ...)- Text-like files are inlined into the prompt for better provider compatibility.
- PDFs:
application/pdf(provider support varies; Google is the most reliable here) - Images:
image/jpeg,image/png,image/webp,image/gif - Audio/Video:
audio/*,video/*(local audio/video files MP3/WAV/M4A/OGG/FLAC/MP4/MOV/WEBM automatically transcribed, when supported by the model)
Notes:
- If a provider rejects a media type, the CLI fails fast with a friendly message.
- xAI models do not support attaching generic files (like PDFs) via the AI SDK; use Google/OpenAI/Anthropic for those.
Use gateway-style ids: <provider>/<model>.
Examples:
openai/gpt-5.4openai/gpt-5.4-miniopenai/gpt-5.4-nanoopenai/gpt-5-miniopenai/gpt-5-nanogithub-copilot/gpt-5.4anthropic/claude-sonnet-4-5xai/grok-4-fast-non-reasoninggoogle/gemini-3-flashzai/glm-4.7minimax/MiniMax-M3openrouter/openai/gpt-5-mini(force OpenRouter)
Note: some models/providers do not support streaming or certain file media types. When that happens, the CLI prints a friendly error (or auto-disables streaming for that model when supported by the provider).
gpt-5.4-mini and gpt-5.4-nano are treated as real model ids; the same shorthand also works under github-copilot/....
Fast mode is a request option, not a model id:
summarize "https://example.com" --model openai/gpt-5.5 --fast --thinking medium
summarize "https://example.com" --model openai/gpt-5.4 --service-tier fast --thinking low--fastis shorthand for--service-tier fast.--service-tier default|fast|priority|flexcontrols OpenAI service tier.fastis the summarize/Codex-facing spelling and is sent to OpenAI asservice_tier="priority".--thinking none|low|medium|high|xhighcontrols OpenAI reasoning effort. Aliases:off→none,min→low,mid/med→medium,x-high/extra-high→xhigh.--service-tier defaultclears a configured tier for one run.
Config equivalent:
{
"model": "openai/gpt-5.5",
"openai": {
"serviceTier": "fast",
"thinking": "medium"
}
}Compatibility aliases still work, but prefer the explicit flags above:
--model gpt-fast/--model fast→openai/gpt-5.5+ fast tier + medium thinking--model openai/gpt-5.5-fast→openai/gpt-5.5+ fast tier
- Text inputs over 10 MB are rejected before tokenization.
- Text prompts are preflighted against the model input limit (LiteLLM catalog), using a GPT tokenizer.
summarize <input> [flags]Use summarize --help or summarize help for the full help text.
--model <provider/model>: which model to use (defaults toauto)--model auto: automatic model selection + fallback (default)--model <name>: use a built-in or config-defined preset (see Configuration)--timeout <duration>:30s,2m,5000ms(default2m)--retries <count>: LLM retry attempts on timeout (default1)--length short|medium|long|xl|xxl|s|m|l|<chars>--language, --lang <language>: output language (auto= match source)--max-output-tokens <count>: hard cap for LLM output tokens--cli [provider]: use a CLI provider (--model cli/<provider>). Supportsclaude,gemini,codex,agent,openclaw,opencode,copilot,agy,pi. If omitted, uses auto selection with CLI enabled.--stream auto|on|off: stream LLM output (auto= TTY only; disabled in--jsonmode)--plain: keep raw output (no ANSI/OSC Markdown rendering)--no-color: disable ANSI colors--theme <name>: CLI theme (aurora,ember,moss,mono)--format md|text: website/file content format (defaulttext)--markdown-mode off|auto|llm|readability: HTML -> Markdown mode (defaultreadability)--preprocess off|auto|always: controlsuvx markitdownusage (defaultauto)- Install
uvx:brew install uv(or https://astral.sh/uv/) - Image-only PDFs can fall back to OpenAI vision OCR when
OPENAI_API_KEYis set; override the OCR model withMARKITDOWN_OCR_MODELor page render DPI withMARKITDOWN_OCR_DPI.
- Install
--extract: print extracted content and exit (URLs only; stdin-is not supported)- Deprecated alias:
--extract-only
- Deprecated alias:
--slides: extract slides for YouTube, direct video URLs, or local video files and render them inline in the summary narrative (auto-renders inline in supported terminals)--slides-ocr: run OCR on extracted slides (requirestesseract)--slides-dir <dir>: base output dir for slide images (default./slides)--slides-scene-threshold <value>: scene detection threshold (0.1-1.0)--slides-max <count>: maximum slides to extract (default6)--slides-min-duration <seconds>: minimum seconds between slides--json: machine-readable output with diagnostics, prompt,metrics, and optional summary--verbose: debug/diagnostics on stderr--metrics off|on|detailed: metrics output (defaulton)
Summarize can use common coding CLIs as local model backends:
codex->--cli codex/--model cli/codex/<model>claude->--cli claude/--model cli/claude/<model>gemini->--cli gemini/--model cli/gemini/<model>agent(Cursor Agent CLI) ->--cli agent/--model cli/agent/<model>openclaw->--cli openclaw/--model cli/openclaw/<model>or--model openclaw/<model>opencode->--cli opencode/--model cli/opencode/<model>(--model cli/opencodeuses the OpenCode runtime default)agy(Antigravity CLI) ->--cli agy/--model cli/agy(uses agy's active session model; per-call model selection is not supported by agy print mode)pi(Pi Coding Agent) ->--cli pi/--model cli/pior--model cli/pi/<model>
Built-in preset:
--model codex-fastruns Codex with GPT-5.5 Fast mode and requirescodex login.
Requirements:
- Binary installed and on
PATH(or setCODEX_PATH,CLAUDE_PATH,GEMINI_PATH,AGENT_PATH,OPENCLAW_PATH,OPENCODE_PATH,AGY_PATH,PI_PATH) - Provider authenticated (
codex login,claude auth,geminilogin flow,agent loginorCURSOR_API_KEY,opencode auth login,agylogin flow orANTIGRAVITY_API_KEY,piuses configured provider API keys)
Quick smoke test:
printf "Summarize CLI smoke input.\nOne short paragraph. Reply can be brief.\n" >/tmp/summarize-cli-smoke.txt
summarize --cli codex --plain --timeout 2m /tmp/summarize-cli-smoke.txt
summarize --cli claude --plain --timeout 2m /tmp/summarize-cli-smoke.txt
summarize --cli gemini --plain --timeout 2m /tmp/summarize-cli-smoke.txt
summarize --cli agent --plain --timeout 2m /tmp/summarize-cli-smoke.txt
summarize --cli openclaw --plain --timeout 2m /tmp/summarize-cli-smoke.txt
summarize --cli opencode --plain --timeout 2m /tmp/summarize-cli-smoke.txt
summarize --cli agy --plain --timeout 2m /tmp/summarize-cli-smoke.txt
summarize --cli pi --plain --timeout 2m /tmp/summarize-cli-smoke.txtSet explicit CLI allowlist/order:
{
"cli": { "enabled": ["codex", "claude", "gemini", "agent", "openclaw", "opencode", "agy", "pi"] }
}Configure implicit auto CLI fallback:
{
"cli": {
"autoFallback": {
"enabled": true,
"onlyWhenNoApiKeys": true,
"order": ["claude", "gemini", "codex", "agent", "openclaw", "opencode"]
}
}
}More details: docs/cli.md
--model auto builds candidate attempts from built-in rules (or your model.rules overrides).
CLI attempts are prepended when:
cli.enabledis set (explicit allowlist/order), or- implicit auto selection is active and
cli.autoFallbackis enabled.
Default fallback behavior: only when no API keys are configured, order claude, gemini, codex, agent, openclaw, opencode, copilot, and remember/prioritize last successful provider (~/.summarize/cli-state.json). Antigravity and pi are opt-in unless you add them to cli.autoFallback.order.
Set explicit CLI attempts:
{
"cli": { "enabled": ["gemini"] }
}Disable implicit auto CLI fallback:
{
"cli": { "autoFallback": { "enabled": false } }
}Note: explicit --model auto does not trigger implicit auto CLI fallback unless cli.enabled is set.
Non-YouTube URLs go through a fetch -> extract pipeline. When direct fetch/extraction is blocked or too thin,
--firecrawl auto can fall back to Firecrawl (if configured).
--firecrawl off|auto|always(defaultauto)--extract --format md|text(defaulttext; if--formatis omitted,--extractdefaults tomdfor non-YouTube URLs)--markdown-mode off|auto|llm|readability(defaultreadability)auto: use an LLM converter when configured; may fall back touvx markitdownllm: force LLM conversion (requires a configured model key)off: disable LLM conversion (still may return Firecrawl Markdown when configured)
- Plain-text mode: use
--format text.
--youtube auto tries best-effort web transcript endpoints first. When captions are not available, it falls back to:
- yt-dlp + Whisper (if
yt-dlpis available): downloads audio, then transcribes with localwhisper.cppwhen installed (preferred), otherwise falls back to Groq (GROQ_API_KEY), AssemblyAI (ASSEMBLYAI_API_KEY), Gemini (GEMINI_API_KEY/ Google aliases), OpenAI (OPENAI_API_KEY), then FAL (FAL_KEY) - Android VR direct audio + the same configured transcription chain when
yt-dlpis unavailable or fails - Apify (if
APIFY_API_TOKENis set): uses a scraping actor (faVsWy9VTSNVIhWpR)
Environment variables for yt-dlp mode:
YT_DLP_PATH- optional path to yt-dlp binary (otherwiseyt-dlpis resolved viaPATH)SUMMARIZE_WHISPER_CPP_MODEL_PATH- optional override for the localwhisper.cppmodel fileSUMMARIZE_WHISPER_CPP_BINARY- optional override for the local binary (default:whisper-cli)SUMMARIZE_DISABLE_LOCAL_WHISPER_CPP=1- disable local whisper.cpp (force remote)GROQ_API_KEY- Groq Whisper transcriptionASSEMBLYAI_API_KEY- AssemblyAI transcriptionGEMINI_API_KEY- Gemini transcription (GOOGLE_GENERATIVE_AI_API_KEY/GOOGLE_API_KEYalso work)OPENAI_API_KEY- OpenAI Whisper transcriptionOPENAI_WHISPER_BASE_URL- optional OpenAI-compatible Whisper endpoint overrideFAL_KEY- FAL AI Whisper fallback
Apify costs money but tends to be more reliable when captions exist.
Speaker-labelled transcripts for YouTube, local audio/video, and direct media URLs:
summarize "https://www.youtube.com/watch?v=..." --extract --diarize
summarize "./interview.mp3" --extract --diarize
summarize "https://cdn.example.com/interview.mp4" --extract --diarize openai
summarize "./interview.mp4" --extract --diarize openai \
--identify-speakers --speaker-at "0:00=Host" --speaker-at "0:12=Guest"
summarize "https://www.youtube.com/watch?v=..." --extract --diarize elevenlabs
summarize "https://www.youtube.com/watch?v=..." --extract --diarize openai --timestamps
summarize "https://www.youtube.com/watch?v=..." --extract --diarize elevenlabs \
--identify-speakers --speaker-profile my-podcast \
--speaker-at "0:12=Host Name" --remember-speakersBare --diarize prefers ElevenLabs Scribe v2 (ELEVENLABS_API_KEY) and falls back to OpenAI
gpt-4o-transcribe-diarize (OPENAI_API_KEY). Speaker changes are emitted as Speaker <label>: ...;
combine with --timestamps for [mm:ss] Speaker <label>: .... Before upload, local video is reduced
to mono 16 kHz MP3 with native or bundled FFmpeg and the same audio file is reused across provider
fallbacks. Local audio is passed through unless OpenAI's upload limit requires compression. YouTube
diarization downloads audio only. When combined with --slides, one yt-dlp invocation downloads
separate audio and slide-quality video streams; diarization uploads the audio while slides reuse the
video. Remote direct media uses its normal audio download path.
YouTube transcript extraction also prints the current public view count and exposes the resolved
video ID and observation timestamp in extracted.sourceMetrics in JSON output.
Long OpenAI recordings are split into bounded chunks; timestamps are reassembled and
chunk-local provider labels stay distinct so label resets cannot silently merge different voices.
--identify-speakers replaces generic labels with names for YouTube and direct media. Repeat --speaker-at <timestamp=name>
for authoritative examples; unresolved labels are inferred with OpenAI GPT-5.5 and only accepted above
the configured confidence threshold. --remember-speakers stores the profile, anchors, and a
transcript-hash-guarded mapping in ~/.summarize/config.json for later runs. See
YouTube speaker identification.
Extract slide screenshots (scene detection via ffmpeg) and optional OCR:
Requirements:
- bundled FFmpeg WebAssembly, or native
ffmpegfor faster extraction and broader codec support yt-dlpfor YouTube video download/stream resolutiontesseractonly when using--slides-ocr
summarize "https://www.youtube.com/watch?v=..." --slides
summarize "https://www.youtube.com/watch?v=..." --slides --slides-ocr
summarize "/path/to/video.webm" --slidesOutputs are written under ./slides/<sourceId>/ (or --slides-dir). OCR results are included in JSON output
(--json) and stored in slides.json inside the slide directory. When scene detection is too sparse, the
extractor also samples at a fixed interval to improve coverage.
When using --slides, supported terminals (kitty/iTerm/Konsole) render inline thumbnails automatically inside the
summary narrative (the model inserts [slide:N] markers). Timestamp links are clickable when the terminal supports
OSC-8 (YouTube/Vimeo/Loom/Dropbox). If inline images are unsupported, Summarize prints a note with the on-disk
slide directory. Local video files stay on the slide-aware path, transcribe in place, and avoid fake download labels.
Use --slides --extract to print the full timed transcript and insert slide images inline at matching timestamps.
Format the extracted transcript as Markdown (headings + paragraphs) via an LLM:
summarize "https://www.youtube.com/watch?v=..." --extract --format md --markdown-mode llmLocal audio/video files are transcribed first, then summarized. --video-mode transcript forces
direct media URLs (and embedded media) through Whisper first. Prefers local whisper.cpp when available; otherwise requires
one of GROQ_API_KEY, ASSEMBLYAI_API_KEY, GEMINI_API_KEY (or Google aliases), OPENAI_API_KEY, or FAL_KEY.
Use --diarize [auto|elevenlabs|openai] for speaker-labelled MP3/MP4 and other supported media;
diarization requires ELEVENLABS_API_KEY or OPENAI_API_KEY.
Summarize can use NVIDIA Parakeet/Canary ONNX models via a local CLI you provide. Auto selection (default) prefers ONNX when configured.
- Setup helper:
summarize transcriber setup - Install
sherpa-onnxfrom upstream binaries/build (Homebrew may not have a formula) - Auto selection: set
SUMMARIZE_ONNX_PARAKEET_CMDorSUMMARIZE_ONNX_CANARY_CMD(no flag needed) - Force a model:
--transcriber parakeet|canary|whisper|auto - Docs:
docs/nvidia-onnx-transcription.md
Run: summarize <url>
- Apple Podcasts
- Spotify
- Amazon Music / Audible podcast pages
- Podbean
- Podchaser
- RSS feeds (Podcasting 2.0 transcripts when available)
- Embedded YouTube podcast pages (e.g. JREPodcast)
Transcription: prefers local whisper.cpp when installed; otherwise uses Groq, AssemblyAI, Gemini, OpenAI, or FAL when keys are set.
--language/--lang controls the output language of the summary (and other LLM-generated text). Default is auto.
When the input is audio/video, the CLI needs a transcript first. The transcript comes from one of these paths:
- Existing transcript (preferred)
- YouTube: uses
youtubei/captionTrackswhen available. - Podcasts: uses Podcasting 2.0 RSS
<podcast:transcript>(JSON/VTT) when the feed publishes it.
- YouTube: uses
- Whisper transcription (fallback)
- YouTube: prefers yt-dlp audio download, then Android VR direct audio, plus Whisper transcription when configured; Apify is a last resort.
- Prefers local
whisper.cppwhen installed + model available. - Otherwise uses cloud transcription in this order: Groq (
GROQ_API_KEY) → AssemblyAI (ASSEMBLYAI_API_KEY) → Gemini (GEMINI_API_KEY/ Google aliases) → OpenAI (OPENAI_API_KEY) → FAL (FAL_KEY).
For direct media URLs, use --video-mode transcript to force transcribe -> summarize:
summarize https://example.com/file.mp4 --video-mode transcript --lang enSingle config location:
~/.summarize/config.json
Run summarize status to inspect the effective default model, configured presets, and model
providers available from config, environment variables, local endpoints, or installed CLIs.
Supported keys today:
{
"model": { "id": "openai/gpt-5-mini" },
"env": { "OPENAI_API_KEY": "sk-..." },
"output": { "length": "long" },
"ui": { "theme": "ember" }
}Shorthand (equivalent):
{
"model": "openai/gpt-5-mini"
}Also supported:
model: { "mode": "auto" }(automatic model selection + fallback; see docs/model-auto.md)model.rules(customize candidates / ordering)models(define presets selectable via--model <preset>; overrides built-ins likefree)env(generic env var defaults; process env still wins)apiKeys(legacy shortcut, mapped to env names; preferenvfor new configs)output.length(default:long; acceptsshort|medium|long|xl|xxl|20k)cache.media(media download cache: TTL 7 days, 2048 MB cap by default;--no-media-cachedisables)media.videoMode: "auto"|"transcript"|"understand"media.embeddedVideo: "auto"|"off"|"prefer"|"both"(defaultauto: combine substantial articles with primary embedded YouTube captions)slides.enabled/slides.max/slides.ocr/slides.dir(defaults for--slides)ui.theme: "aurora"|"ember"|"moss"|"mono"openai.useChatCompletions: true(force OpenAI-compatible chat completions)openai.serviceTier: "fast"|"priority"|"flex"(use"fast"for the friendly alias)openai.thinking/openai.reasoningEffort: "none"|"low"|"medium"|"high"|"xhigh"openai.textVerbosity: "low"|"medium"|"high"
Note: the config is parsed leniently (JSON5), but comments are not allowed. Unknown keys are ignored.
Media cache defaults:
{
"cache": {
"media": { "enabled": true, "ttlDays": 7, "maxMb": 2048, "verify": "size" }
}
}Note: --no-cache bypasses summary caching only (LLM output). Extract/transcript caches still apply. Use --no-media-cache to skip media files.
Precedence:
--modelSUMMARIZE_MODEL~/.summarize/config.json- default (
auto)
Theme precedence:
--themeSUMMARIZE_THEME~/.summarize/config.json(ui.theme)- default (
aurora)
Environment variable precedence:
- process env
~/.summarize/config.json(env)~/.summarize/config.json(apiKeys, legacy)
Set the key matching your chosen --model:
-
Optional fallback defaults can be stored in config:
~/.summarize/config.json->"env": { "OPENAI_API_KEY": "sk-..." }- process env always takes precedence
- legacy
"apiKeys"still works (mapped to env names)
-
OPENAI_API_KEY(foropenai/...) -
NVIDIA_API_KEY(fornvidia/...) -
MINIMAX_API_KEY(forminimax/...) -
ANTHROPIC_API_KEY(foranthropic/...) -
XAI_API_KEY(forxai/...) -
Z_AI_API_KEY(forzai/...; supportsZAI_API_KEYalias) -
GEMINI_API_KEY(forgoogle/...)- also accepts
GOOGLE_GENERATIVE_AI_API_KEYandGOOGLE_API_KEYas aliases
- also accepts
OpenAI-compatible chat completions toggle:
OPENAI_USE_CHAT_COMPLETIONS=1(or setopenai.useChatCompletionsin config)
UI theme:
SUMMARIZE_THEME=aurora|ember|moss|monoSUMMARIZE_TRUECOLOR=1(force 24-bit ANSI)SUMMARIZE_NO_TRUECOLOR=1(disable 24-bit ANSI)
OpenRouter (OpenAI-compatible):
- Set
OPENROUTER_API_KEY=... - Prefer forcing OpenRouter per model id:
--model openrouter/<author>/<slug> - Built-in preset:
--model free(uses a default set of OpenRouter:freemodels)
Quick start: make free the default (keep auto available)
summarize refresh-free --set-default
summarize "https://example.com"
summarize "https://example.com" --model autoRegenerates the free preset (models.free in ~/.summarize/config.json) by:
- Fetching OpenRouter
/models, filtering:free - Skipping models that look very small (<27B by default) based on the model id/name
- Testing which ones return non-empty text (concurrency 4, timeout 10s)
- Picking a mix of smart-ish (bigger
context_length/ output cap) and fast models - Refining timings and writing the sorted list back
If --model free stops working, run:
summarize refresh-freeFlags:
--runs 2(default): extra timing runs per selected model (total runs = 1 + runs)--smart 3(default): how many smart-first picks (rest filled by fastest)--min-params 27b(default): ignore models with inferred size smaller than N billion parameters--max-age-days 180(default): ignore models older than N days (set 0 to disable)--set-default: also sets"model": "free"in~/.summarize/config.json
Example:
OPENROUTER_API_KEY=sk-or-... summarize "https://example.com" --model openrouter/meta-llama/llama-3.1-8b-instruct:free
OPENROUTER_API_KEY=sk-or-... summarize "https://example.com" --model openrouter/minimax/minimax-m2.5If your OpenRouter account enforces an allowed-provider list, make sure at least one provider
is allowed for the selected model. When routing fails, summarize prints the exact providers to allow.
Legacy: OPENAI_BASE_URL=https://openrouter.ai/api/v1 (and either OPENAI_API_KEY or OPENROUTER_API_KEY) also works.
NVIDIA API Catalog (OpenAI-compatible; free credits):
- Set
NVIDIA_API_KEY=... - Optional:
NVIDIA_BASE_URL=https://integrate.api.nvidia.com/v1 - Credits: API Catalog trial starts with 1000 free API credits on signup (up to 5000 total via “Request More” in the API Catalog profile)
- Pick a model id from
/v1/models(examples: faststepfun-ai/step-3.5-flash, strong but slowerz-ai/glm5)
export NVIDIA_API_KEY="nvapi-..."
summarize "https://example.com" --model nvidia/stepfun-ai/step-3.5-flashZ.AI (OpenAI-compatible):
Z_AI_API_KEY=...(orZAI_API_KEY=...)- Optional base URL override:
Z_AI_BASE_URL=...
MiniMax (OpenAI-compatible):
- Set
MINIMAX_API_KEY=... - Optional base URL override:
MINIMAX_BASE_URL=...(defaulthttps://api.minimax.io/v1; use the China endpoint or a proxy if needed) - Pick a MiniMax model id (e.g.
MiniMax-M3,MiniMax-M2.5) using MiniMax's exact casing - Reasoning is requested through MiniMax's separated response fields and omitted from summary text
export MINIMAX_API_KEY="..."
summarize "https://example.com" --model minimax/MiniMax-M3Optional services:
FIRECRAWL_API_KEY(website extraction fallback)YT_DLP_PATH(path to yt-dlp binary for audio extraction)GROQ_API_KEY(Groq Whisper transcription)ASSEMBLYAI_API_KEY(AssemblyAI transcription)ELEVENLABS_API_KEY(ElevenLabs Scribe v2 speaker diarization)GEMINI_API_KEY/GOOGLE_GENERATIVE_AI_API_KEY/GOOGLE_API_KEY(Gemini transcription)OPENAI_API_KEY/OPENAI_WHISPER_BASE_URL(OpenAI Whisper transcription)FAL_KEY(FAL AI API key for audio transcription via Whisper)APIFY_API_TOKEN(YouTube transcript fallback)
The CLI uses the LiteLLM model catalog for model limits (like max output tokens):
- Downloaded from:
https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json - Cached at:
~/.summarize/cache/
Recommended (minimal deps):
@steipete/summarize-core/content@steipete/summarize-core/prompts
Compatibility (pulls in CLI deps):
@steipete/summarize/content@steipete/summarize/prompts
pnpm install
pnpm check- Docs index: docs/README.md
- CLI providers and config: docs/cli.md
- Auto model rules: docs/model-auto.md
- Website extraction: docs/website.md
- YouTube handling: docs/youtube.md
- Media pipeline: docs/media.md
- Config schema and precedence: docs/config.md
- "Receiving end does not exist": Chrome did not inject the content script yet.
- Extension details -> Site access -> On all sites (or allow this domain)
- Reload the tab once.
- "Failed to fetch" / daemon unreachable:
summarize daemon status- Logs:
~/.summarize/logs/daemon.err.log
License: MIT


