llm-tool-brave
brave Search API plugin/tool for Simon Willison's LLM.
Default api method: context, backed by brave's LLM Context API.
It returns pre-extracted, token-budgeted grounding content for the model running in llm.
NB: This plugin does not shell out to bx;
it calls https://api.search.brave.com/res/v1 directly with the Python standard library.
AGENTS.md points at this file, so keep operational project knowledge here.
Demo
Quick Start
Quick in-place usage
uv sync # see explanation below
uv run pytest # optional
uv run llm plugins # shall show llm-tool-brave
uv run llm tools list | grep -i brave
uv sync installs this package into .venv because [tool.uv] package = true.
The default dev dependency group makes uv run pytest work without extra flags.
Runtime-only local check:
uv run --no-dev llm plugins
uv run --no-dev llm tools list | grep -i brave
Install into a global llm environment from local dir:
llm install -e .
llm plugins
Install into a global llm after PyPi publishing:
llm install llm-tool-brave
Configuration (one-time)
Set a brave Search API key:
llm keys set brave
Lookup order: stored key alias brave, brave-search, then env BRAVE_SEARCH_API_KEY.
Avoid raw API keys in toolbox constructor arguments such as
-T 'Brave(api_key="...")'. This is not the standard llm plugin approach
(key-requiring plugins resolve keys via llm keys or env vars), and llm 0.32+
persists toolbox constructor arguments to the logs database and replays them
when continuing conversations with llm -c. As a safety net this plugin scrubs
api_key from that persisted config, which means a conversation started with a
raw constructor key can only be continued if the key is also available via
llm keys or BRAVE_SEARCH_API_KEY. The api_key argument remains supported
for the Python API and tests.
Usage
# default: only context tool is enabled; --td optional: shows tools calls by llm
llm -T Brave --td 'Search current web context for the latest llm tool plugin documentation and summarize it.'
# selected tools
llm -T 'Brave("context,web,news")' 'Find current uv release notes and summarize the important changes.'
# all implemented endpoints
llm -T 'Brave("all")' 'Find coffee shops near Warsaw city center and summarize the options.'
Tools
| Tool | Endpoint | Plan | Use |
|---|---|---|---|
context |
/llm/context |
Search | Main RAG/LLM grounding tool with extracted text chunks, tables, code, and source metadata. |
web |
/web/search |
Search | Traditional web results with URLs, snippets, and rich result types. |
news |
/news/search |
Search | Recent news with freshness filters. |
images |
/images/search |
Search | Image results and thumbnails. |
videos |
/videos/search |
Search | Video metadata. |
places |
/local/place_search |
Search | Businesses, landmarks, POIs, cities, and addresses. |
suggest |
/suggest/search |
Suggest | Query autocomplete and rich entity suggestions. |
spellcheck |
/spellcheck/search |
Spellcheck | Pre-search query correction. |
answers |
/chat/completions |
Answers | brave-generated answer. Prefer context when your current LLM should synthesize. |
Enable selected tools with Brave("context,web,news"); enable all with
Brave("all").
Model-visible tool names carry the toolbox class prefix: Brave_context,
Brave_web, and so on. The prefix must match the registered class name so that
llm 0.32+ can map logged tool calls back to this toolbox and continue
conversations with llm -c without repeating the -T option.
Tool schemas are sent to the model with every request, so tool methods expose
only per-query parameters. Everything user- or environment-level lives on the
Brave() constructor instead (see Toolbox Settings) and never costs prompt
tokens.
Context Tool
Use Brave_context first for web research, docs lookup, fact-checking, and RAG.
llm -T Brave --td 'Use brave context to find Python 3.13 pathlib changes and explain the practical impact.'
llm -T Brave --td 'Use brave context, restricted to docs.python.org and peps.python.org, to answer: what changed in Python 3.13 typing?'
Per-call parameters (the schema the model sees — deliberately short):
| Parameter | brave API field | Default | Range / values |
|---|---|---|---|
query |
q |
required | search query |
count |
count |
20 |
1-50 |
max_tokens |
maximum_number_of_tokens |
8192 |
1024-32768 |
threshold |
context_threshold_mode |
balanced |
strict, balanced, lenient, disabled |
freshness |
freshness |
none | pd, pw, pm, py, or YYYY-MM-DDtoYYYY-MM-DD |
include_sites, exclude_sites |
goggles |
none | comma-separated domains |
Each call is bounded by max_tokens before returning to llm. Multiple searches
consume multiple tool responses plus JSON/source metadata. Invalid documented brave
ranges are rejected before the API request.
Toolbox Settings
All other knobs are set once on the Brave() constructor and applied to every
call. With the llm CLI, pass either one positional value or keyword arguments —
the spec parser does not support mixing both:
llm -T 'Brave(tools="context,web", country="PL", search_lang="pl")' 'Find current uv release notes.'
| Setting | Default | Used by |
|---|---|---|
country |
US |
all tools |
search_lang |
en |
all tools (also lang for suggest, spellcheck) |
safesearch |
moderate |
web, images, videos |
spellcheck |
true |
context, images |
goggles |
none | raw brave Goggles rules for context, web, news |
enable_local |
none | context |
extra_snippets |
none | web |
rich |
false |
suggest |
units |
metric |
places |
max_urls |
20 (1-50) |
context budget |
max_snippets |
50 (1-100) |
context budget |
max_tokens_per_url |
4096 (512-8192) |
context budget |
max_snippets_per_url |
50 (1-100) |
context budget |
lat, long, city, state, loc_country, postal_code |
none | context location headers |
research_iterations |
3 |
answers research mode |
research_seconds |
120 |
answers research mode |
Context budget settings are validated at construction time.
Untrusted Web Content
Search result text is external and untrusted. The plugin wraps snippets,
descriptions, and brave-generated answer content with compact
BRAVE_UNTRUSTED_CONTENT markers and adds one security_notice field. URLs,
titles, source metadata, and structured fields stay intact.
This is a prompt-level guardrail, not a security boundary. Be careful combining search tools with tools that can read private data, execute commands, send messages, or exfiltrate information.
Python API
import llm
from llm_tool_brave import Brave
model = llm.get_model("gpt-5.4-mini")
response = model.chain(
"Use brave context to find the current LLM tool plugin docs and summarize the API shape.",
tools=[Brave()],
)
print(response.text())
tools = [Brave("context,web,news", country="PL", search_lang="pl")]
Build And Release
uv build
Publishing uses .github/workflows/publish.yml: full Python test matrix, uv build,
then PyPI Trusted Publishing. Before the first release, configure PyPI for repository
rdslw/llm-tool-brave, workflow publish.yml, environment pypi.
uv.lock is intentionally not committed: this is a library, so the lockfile never
ships to users, and unlocked CI resolves fresh against llm>=0.27 — an early
warning when a new llm release breaks the plugin. [tool.uv] exclude-newer
keeps brand-new package releases out of every resolution as a supply-chain guard.
Release:
- Update
versioninpyproject.toml. PyPI versions are immutable. - Run
uv sync --all-groups,uv run pytest, anduv build. - Commit, tag, push, then create a GitHub release from that tag.
git add pyproject.toml
git commit -m "Release 0.1.0"
git tag -a 0.1.0 -m "Release 0.1.0"
git push origin master
git push origin 0.1.0
The release event triggers Publish to PyPI. workflow_dispatch is available for
manual publishing, but normal versions should publish from release tags.
Post-publish smoke test:
uvx --from llm llm install llm-tool-brave
llm plugins
Direct API Calls vs. bx
This plugin manually constructs HTTPS requests to the brave Search API instead of
invoking bx. Tradeoffs:
- Packaging: direct API calls avoid requiring a separate
bxbinary. - LLM ergonomics: direct Python methods expose cleaner structured tool schemas.
- Secrets: direct
llm keys/BRAVE_SEARCH_API_KEYintegration avoids command-line API keys. - Feature coverage:
bxmay expose brave API features, flags, config, and workflows not implemented here. - Errors: direct calls return structured tool errors;
bxhas mature CLI exit codes and diagnostics. - Performance/control: direct HTTP avoids subprocess and shell quoting overhead, but this plugin owns request/response behavior.
- API changes: because
bxis developed by brave, it is more likely to pick up brave Search API changes quickly. - Shared utility: an installed
bxCLI is also useful for humans, scripts, and other tools, and is easy to test directly.
Metadata
Release files for llm-tool-brave 0.10.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| llm_tool_brave-0.10.0.tar.gz | 249.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| llm_tool_brave-0.10.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 262.6 kB
Release files / llm_tool_brave-0.10.0.tar.gz
| Download URL | llm_tool_brave-0.10.0.tar.gz |
|---|---|
| Size | 249.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
71e0d3f405900eb7d10d2022158d8102dcad99d2f22e398d7985888c20f95c16
|
|
BLAKE2b-256 checksum How to use checksums |
be66c03cdc65d1f3384eb0054888fcff51cd230e19d07b7aa97f922f0b3de9cf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 8, 2026.
Transparency logRelease files / llm_tool_brave-0.10.0-py3-none-any.whl
| Download URL | llm_tool_brave-0.10.0-py3-none-any.whl |
|---|---|
| Size | 13.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
80921840e80281ce0668d743ed5a75b57ce082cdf5ac15b470aee1fc640aac4b
|
|
BLAKE2b-256 checksum How to use checksums |
d7b19a0060b8af8e847ac6f32c6b81495ae5ce10013d9d21082fd7b391502f16
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 8, 2026.
Transparency log