Skip to main content

Content compression for AI agents. Extract once, render per query.

Project description

Brief Logo

PyPI Python 3.12+ License: MIT

Brief

Reading the web is the most expensive thing your agent does, and the least of what it's good at.

Brief reads content so your agent doesn't have to. Give it a URL and a question, and it extracts, summarizes, and caches the answer. Webpages, videos, PDFs, Reddit, GitHub, all through one interface.

from brief import brief

# Is this page even relevant? (~1 sentence)
brief("https://fastapi.tiangolo.com/", "async support", depth=0)

# What do I need to know? (summary + key points)
brief("https://fastapi.tiangolo.com/", "async support", depth=1)

# Give me everything. (detailed analysis with examples)
brief("https://fastapi.tiangolo.com/", "async support", depth=2)

Every answer is cached as a plain .brief file. Ask once, reuse forever. A team of agents can share research without repeating work. One agent investigates, another reasons, another writes, and nobody re-reads the same source.

The more your system runs, the more it already knows.

# Agent A researches FastAPI (extraction + LLM call)
brief("https://fastapi.tiangolo.com/", "async support", depth=2)

# Minutes later, Agent B is writing a comparison doc.
# Same URL, same question. Instant. No fetch, no LLM, no tokens.
check_brief("https://fastapi.tiangolo.com/")
# → "async-support-deep.brief: FastAPI handles async natively..."

# Agent B goes deeper with a new question. One LLM call, no re-extraction.
brief("https://fastapi.tiangolo.com/", "error handling", depth=1)

Agent A paid the cost. Agent B got it free. Agents should spend tokens on reasoning, not searching.

Install

Requires Python 3.12+.

pip install getbrief

Brief uses any OpenAI-compatible LLM for summarization. Create a .env file:

BRIEF_LLM_API_KEY=sk-or-v1-your-key
BRIEF_LLM_BASE_URL=https://openrouter.ai/api/v1
BRIEF_LLM_MODEL=google/gemma-3-4b-it:free # any OpenRouter free or cheap model works

Free models work great. Also works with OpenAI, Ollama (local), and Groq. See .env.example for all options.

Common patterns

Triage many URLs, then go deep on what matters

from brief import brief_batch, brief

# Scan 10 URLs for pennies. Which ones are relevant?
headlines = brief_batch([
    "https://docs.python.org/3/library/asyncio.html",
    "https://fastapi.tiangolo.com/",
    "https://flask.palletsprojects.com/",
], query="python async web framework", depth=0)

# Go deep on the one that matters
detail = brief("https://fastapi.tiangolo.com/", "async support", depth=2)

Compare sources

from brief import compare

# Briefs each source, then synthesizes a comparison
result = compare(
    ["https://fastapi.tiangolo.com/", "https://flask.palletsprojects.com/"],
    query="how do they handle middleware",
    depth=1,
)

Check what's already been researched

from brief import check_brief

# Overview of all sources
check_brief()

# Detail for a specific URL
check_brief("https://fastapi.tiangolo.com/")

Depth levels

depth=0   headline    one sentence, is this worth reading?
depth=1   summary     2-3 sentences + key points (default)
depth=2   deep dive   detailed analysis with specifics, examples, trade-offs

Each (query, depth) pair produces its own .brief file.

Content types

Brief handles five content types with the same interface:

  • Webpagestrafilatura strips navigation, ads, and scripts. Falls back to httpx, then optionally Playwright for bot-protected sites.
  • Videosyt-dlp fetches captions. If none exist, faster-whisper transcribes audio locally.
  • PDFspymupdf extracts text page by page.
  • Reddit — fetches post content and top comments via Reddit's JSON API.
  • GitHub — fetches repo metadata, README, file tree, and open issues via GitHub's API.

Interfaces

Python

from brief import brief, brief_batch, compare, check_brief

CLI

brief --uri "https://example.com" --query "key takeaways"
brief --uri "https://example.com" --depth 0
brief --compare --batch "https://url1.com" --batch "https://url2.com" --query "compare"
brief --list

MCP

{
  "mcpServers": {
    "brief": {
      "command": "uvx",
      "args": ["--from", "getbrief", "brief-mcp"],
      "env": {
        "BRIEF_LLM_API_KEY": "sk-or-v1-your-key",
        "BRIEF_LLM_BASE_URL": "https://openrouter.ai/api/v1",
        "BRIEF_LLM_MODEL": "google/gemma-3-4b-it:free"
      }
    }
  }
}

This gives your agent three tools:

  • brief_content — brief a URL with a query at depth 0–2
  • check_existing_brief — no URI = overview of all sources, with URI = what's been asked about it
  • compare_sources — compare multiple URLs with synthesis + TRAIL breadcrumbs

HTTP API

uvicorn brief.api:app --port 8080
# Brief a URL
curl -X POST http://localhost:8080/brief \
  -H "Content-Type: application/json" \
  -d '{"uri": "https://fastapi.tiangolo.com/", "query": "async support", "depth": 1}'

# List all briefs
curl http://localhost:8080/briefs

# Health check
curl http://localhost:8080/health

The .briefs/ folder

Every URL gets its own subdirectory. Each (query, depth) adds a new .brief file:

.briefs/
├── fastapi-tiangolo-com/
│   ├── _source.json                 raw extraction, no LLM output
│   ├── async-support.brief          depth=1 answer
│   └── async-support-deep.brief     depth=2 answer, same query, richer
├── _comparisons/                    cached cross-source comparisons
└── _index.sqlite3                   fast lookups

Each .brief file includes a TRAIL section at the bottom, listing sibling briefs for the same source:

─── TRAIL ──────────────────────────────────────
→ async-support.brief
→ error-handling-deep.brief
→ _source.json

When an agent opens any .brief file, it instantly sees what else has already been asked about that source. No API call, no index lookup, just read the file. This means agents can build on each other's research naturally.

Configuration

Brief uses any OpenAI-compatible provider. OPENAI_API_KEY also works as a fallback if BRIEF_LLM_API_KEY is not set.

For video transcription without captions:

pip install getbrief[transcribe]  # installs faster-whisper

For bot-protected sites (Cloudflare, etc.):

pip install getbrief[playwright]
playwright install chromium

For GitHub repos, the public API is rate-limited to 60 requests/hour. Set a token for higher limits:

GITHUB_TOKEN=ghp_your-token

Troubleshooting

  • Paywalled / auth-protected content — Brief returns a clear error for 401/403/429 responses. It cannot extract content behind logins or paywalls.
  • Bot protection (Cloudflare, etc.) — Install Playwright: pip install getbrief[playwright] && playwright install chromium
  • Stale or bad summary — Use --force to skip cache and re-extract: brief --uri <URL> --force
  • Clear all cached data — Delete the .briefs/ folder.
  • LLM not responding — Check your .env file has valid API keys. Brief falls back to a heuristic summary if the LLM is unavailable.

Contributing

Brief is designed to be easy to extend. New extractors live in brief/extractors/ and each one is a single file implementing one function:

def extract(uri: str) -> list[dict[str, Any]]:
    """Return a list of chunks with 'text' and 'start_sec' keys."""

Contributions welcome: new content types, better summarization, CLI improvements, or API enhancements.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

getbrief-0.6.1.tar.gz (37.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

getbrief-0.6.1-py3-none-any.whl (40.4 kB view details)

Uploaded Python 3

File details

Details for the file getbrief-0.6.1.tar.gz.

File metadata

  • Download URL: getbrief-0.6.1.tar.gz
  • Upload date:
  • Size: 37.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for getbrief-0.6.1.tar.gz
Algorithm Hash digest
SHA256 c8480be637474606db0f3dd119c1e1a4efa55d632ac2eb8e0f5ef460ab28dfc5
MD5 5d2b1df9b57d487fcfb8186bde1a8f14
BLAKE2b-256 5a303df4a01c4ae770ffcbc44b6f89078fdd9ca4c0ef97bafd8a1c3291402e2d

See more details on using hashes here.

Provenance

The following attestation bundles were made for getbrief-0.6.1.tar.gz:

Publisher: publish.yml on aulesy/brief

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file getbrief-0.6.1-py3-none-any.whl.

File metadata

  • Download URL: getbrief-0.6.1-py3-none-any.whl
  • Upload date:
  • Size: 40.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for getbrief-0.6.1-py3-none-any.whl
Algorithm Hash digest
SHA256 89de72a7bbfb9fd78eb9766442254af0701eaa925bdac5947ef017c7d1036cff
MD5 59403a19d9097940722a656604769831
BLAKE2b-256 3a15198fe7ebdd199d60868b4081223f3a45fb2e9578e5d1be7c1252eadb7183

See more details on using hashes here.

Provenance

The following attestation bundles were made for getbrief-0.6.1-py3-none-any.whl:

Publisher: publish.yml on aulesy/brief

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page