Python CLI for creating concise briefs from text, files, URLs, YouTube videos, and PDFs.
Project description
Briefly AI
Python CLI for creating concise briefs from text, files, URLs, YouTube videos, and PDFs.
Supported Inputs
- Plain text
- Local text/Markdown files
- Local and remote PDFs
- Web pages
- YouTube videos with captions
- YouTube videos without captions via Groq Whisper fallback
- Stdin
Quickstart
1. Clone the repo
git clone https://github.com/Rahat-Kabir/briefly-ai
cd briefly-ai
2. Install dependencies
uv sync
On Windows, if uv cache or hardlink warnings appear, use the project-local cache and copy mode:
$env:UV_CACHE_DIR='.uv-cache'
$env:UV_LINK_MODE='copy'
uv sync
3. Set your API key
For OpenAI models, set OPENAI_API_KEY:
$env:OPENAI_API_KEY='your_openai_api_key'
This sets the key for the current PowerShell session. To save it permanently for your Windows user:
[Environment]::SetEnvironmentVariable('OPENAI_API_KEY', 'your_openai_api_key', 'User')
Open a new terminal after setting it permanently.
Other providers use their own environment variables, such as
ANTHROPIC_API_KEY, GEMINI_API_KEY, or other provider keys supported by
LiteLLM.
Common provider keys:
$env:OPENAI_API_KEY='your_openai_api_key'
$env:ANTHROPIC_API_KEY='your_anthropic_api_key'
$env:GEMINI_API_KEY='your_gemini_api_key'
$env:GROQ_API_KEY='your_groq_api_key'
$env:OPENROUTER_API_KEY='your_openrouter_api_key'
Example model ids:
uv run briefly "Hello" --model openai/gpt-4o-mini
uv run briefly "Hello" --model anthropic/claude-sonnet-4-5
uv run briefly "Hello" --model groq/llama-3.1-8b-instant
uv run briefly "Hello" --model openrouter/openai/gpt-4o-mini
4. Set a default model
uv run briefly config init --model <model-id>
Example:
uv run briefly config init --model openai/gpt-4o-mini
The example above uses an OpenAI model, so it requires OPENAI_API_KEY.
5. Run your first brief
uv run briefly "Briefly turns long content into concise briefs."
Or pass a model for one command:
uv run briefly "Briefly turns long content into concise briefs." --model openai/gpt-4o-mini
Usage
Briefly needs an LLM model for briefing. You can either save a default model
once, or pass --model on each command.
Set a default model
uv run briefly config init --model <model-id>
This writes ~/.briefly/config.json. After that, regular commands can omit
--model:
uv run briefly "Paste or type any text here."
uv run briefly notes.txt
uv run briefly https://example.com
To use a different model for one command:
uv run briefly notes.txt --model <model-id>
One valid model id is openai/gpt-4o-mini; use any LiteLLM-supported model id
that matches your API keys.
You can also define named model presets in ~/.briefly/config.json:
{
"model": "provider/model-id",
"models": {
"fast": "provider/model-id"
}
}
Then run:
uv run briefly notes.txt --model fast
config init refuses to overwrite an existing config unless --force is
passed.
Common examples
uv run briefly "Paste or type any text here."
uv run briefly "Long article text..." --length short
uv run briefly "Long article text..." --length long
uv run briefly "Meeting notes..." --brief-type action
uv run briefly https://example.com
Current state: early CLI foundation. Briefly can resolve text/file/stdin input, print extracted text, and generate length-controlled text briefs through LiteLLM. Brief types shape the prompt for standard, executive, action, study, and decision-focused output. Config-backed model selection, trafilatura-backed HTML URL briefing, YouTube caption briefing, Groq Whisper fallback, token streaming, structured JSON output, and local cache are available. YouTube transcript timestamps are available in extract and briefing input.
Brief a file
uv run briefly notes.txt
uv run briefly paper.pdf
uv run briefly paper.pdf --extract
uv run briefly https://example.com/paper.pdf --extract
Local and remote PDF input uses pdfplumber; the title comes from PDF metadata when present, otherwise the filename or URL. Scanned/image-only PDFs raise a clear error.
Brief a YouTube video
uv run briefly https://youtu.be/v4F1gFy-hqg
uv run briefly https://www.youtube.com/watch?v=v4F1gFy-hqg --extract
uv run briefly https://www.youtube.com/watch?v=v4F1gFy-hqg --extract --timestamps
uv run briefly https://youtu.be/v4F1gFy-hqg --extract --json
Briefly fetches the video's captions through YouTube's Android InnerTube API.
Works for youtube.com, youtu.be, /shorts, /embed, and /live URLs.
Use --timestamps to print transcript lines with [m:ss] or [h:mm:ss]
timestamps.
If YouTube captions are missing, Briefly can fall back to Groq Whisper. Install
yt-dlp and set GROQ_API_KEY:
$env:GROQ_API_KEY='your_groq_api_key'
uv run briefly "https://youtu.be/example" --extract
Extract mode
Extract mode resolves and prints input without an LLM call.
uv run briefly "Some text" --extract
uv run briefly README.md --extract
uv run briefly https://example.com --extract
uv run briefly https://example.com --extract --json
echo "Piped text" | uv run briefly - --extract
URL extraction uses trafilatura first, with BeautifulSoup fallback. Use
--output-format markdown to preserve Markdown-style headings and links.
Brief types
--brief-type changes the purpose of the brief while --length still controls
size.
uv run briefly report.pdf --brief-type executive
uv run briefly meeting.txt --brief-type action
uv run briefly article.md --brief-type study
uv run briefly proposal.pdf --brief-type decision
Available types:
| Type | Purpose |
|---|---|
standard |
General concise brief; this is the default and preserves existing behavior |
executive |
Business or leadership brief focused on takeaways, impact, risks, and attention areas |
action |
Decisions, action items, owners, deadlines, blockers, and follow-ups without inventing missing details |
study |
Core concepts, definitions, examples, and review points for learning |
decision |
Options, tradeoffs, risks, supported recommendation, and missing evidence |
Options
uv run briefly --help
| Flag | Description |
|---|---|
--extract |
Print resolved input without briefing |
--model TEXT |
LLM model id or configured model preset |
--length TEXT |
Brief length: short, medium, long, xl, xxl, or a char count like 500 |
--brief-type TEXT |
Brief type: standard, executive, action, study, or decision |
--output-format TEXT |
Output format: text or markdown |
--max-input-chars TEXT |
Truncate input to this many characters, e.g. 50k |
--max-tokens TEXT |
Maximum output tokens |
--stream TEXT |
Streaming mode: on, off, or auto (TTY) |
--json |
Print structured JSON; streaming is disabled in JSON mode |
--timestamps |
Include YouTube transcript timestamps when available |
--skip-cache |
Skip cache reads and writes |
Cache
Briefly stores URL extraction and summary results in ~/.briefly/cache.sqlite.
uv run briefly cache stats
uv run briefly cache clear
uv run briefly https://example.com --skip-cache
Default TTLs: URL extraction cache expires after 7 days; summary cache expires after 30 days. Override both with:
{
"cache": {
"ttlDays": 14
}
}
Development
uv run pytest
uv run ruff check
On Windows, use the repo-local uv cache if the default cache fails:
$env:UV_CACHE_DIR='.uv-cache'; uv run pytest
$env:UV_CACHE_DIR='.uv-cache'; uv run ruff check
Project Structure
briefly-ai/
|-- pyproject.toml
|-- uv.lock
|-- AGENTS.md
|-- CLAUDE.md
|-- LICENSE
|-- README.md
|
|-- docs/
| |-- RELEASE_v0.2.md
| |-- progress.md
| |-- tech_spec.md
| `-- testing.md
|
|-- packages/
| |-- briefly-core/
| | |-- pyproject.toml
| | `-- src/briefly_core/
| | |-- __init__.py
| | |-- briefing.py
| | |-- cache.py
| | |-- content.py
| | |-- config.py
| | |-- flags.py
| | |-- input.py
| | |-- llm.py
| | |-- pdf.py
| | `-- youtube.py
| |
| `-- briefly-cli/
| |-- pyproject.toml
| `-- src/briefly_cli/
| |-- __init__.py
| |-- main.py
| `-- commands/
| |-- __init__.py
| |-- brief.py
| |-- cache.py
| |-- config.py
| |-- daemon.py
| |-- slides.py
| `-- transcriber.py
|
|-- tests/
| |-- cli/
| | |-- conftest.py
| | |-- test_cache_cli.py
| | |-- test_cache_commands.py
| | |-- test_config_init.py
| | |-- test_config_model.py
| | |-- test_extract.py
| | |-- test_help.py
| | |-- test_json_output.py
| | |-- test_pdf_cli.py
| | |-- test_stream.py
| | `-- test_youtube_cli.py
| `-- core/
| |-- test_briefing.py
| |-- test_cache.py
| |-- test_content.py
| |-- test_config.py
| |-- test_flags.py
| |-- test_input.py
| |-- test_llm.py
| |-- test_pdf.py
| `-- test_youtube.py
Docs: tech spec, progress, testing.
License
MIT. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file briefly_ai-0.1.0.tar.gz.
File metadata
- Download URL: briefly_ai-0.1.0.tar.gz
- Upload date:
- Size: 24.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d534ca2db65138f8deeb8192e6ef8aaa826142135c5163ff85d1b12a28bb0080
|
|
| MD5 |
f4d4ee6f90e8964bbaf1fe0e20b034d3
|
|
| BLAKE2b-256 |
786cf23bae366adf149e17d60d5e2d015ae8cccae90a0e5aeafd96915e89df3b
|
File details
Details for the file briefly_ai-0.1.0-py3-none-any.whl.
File metadata
- Download URL: briefly_ai-0.1.0-py3-none-any.whl
- Upload date:
- Size: 31.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
232e0bbe87595702a5aef233ead6c1ae02e3d2cf9aa5e5e0996ddbd1ecae5558
|
|
| MD5 |
9e00f4e212cb1b25cc0ed300d91a1491
|
|
| BLAKE2b-256 |
4e66e01540a71d39401fb0f318e0ec69c3f2ba1e56a323708c29290e04a80f38
|