brave Search API tool for Simon Willison's LLM
Project description
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 -E '^ +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 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. LLM may log those; llm keys
or BRAVE_SEARCH_API_KEY keeps secrets out of prompts and tool-call logs.
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").
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.
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 llm_tool_brave-0.9.1.tar.gz.
File metadata
- Download URL: llm_tool_brave-0.9.1.tar.gz
- Upload date:
- Size: 247.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c42f6ef2d226477259019cff33d4574b6f2aa3b83c9f1fbb1eab59f80671998e
|
|
| MD5 |
d27f491d175deeaaaeaf29ee58295f5c
|
|
| BLAKE2b-256 |
3bc9a9a51192bd536fbf68460dd368b16f88a0bf45890854bf664983d8906466
|
Provenance
The following attestation bundles were made for llm_tool_brave-0.9.1.tar.gz:
Publisher:
publish.yml on rdslw/llm-tool-brave
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
llm_tool_brave-0.9.1.tar.gz -
Subject digest:
c42f6ef2d226477259019cff33d4574b6f2aa3b83c9f1fbb1eab59f80671998e - Sigstore transparency entry: 1783702984
- Sigstore integration time:
-
Permalink:
rdslw/llm-tool-brave@1c7aff9f120bcbf2e875d419d5133fe05ad3fa7d -
Branch / Tag:
refs/tags/v0.9.1 - Owner: https://github.com/rdslw
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1c7aff9f120bcbf2e875d419d5133fe05ad3fa7d -
Trigger Event:
release
-
Statement type:
File details
Details for the file llm_tool_brave-0.9.1-py3-none-any.whl.
File metadata
- Download URL: llm_tool_brave-0.9.1-py3-none-any.whl
- Upload date:
- Size: 12.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ae916818bd5244ed14cfa2757dc456c94b334c819b1eef1f87b5d5ab04434601
|
|
| MD5 |
32a70dbfab8133fbc54463469f1dda15
|
|
| BLAKE2b-256 |
84e57d9cb39005845d79a4d5df778e39c13cae69c2526aa9d16f66116a705cb8
|
Provenance
The following attestation bundles were made for llm_tool_brave-0.9.1-py3-none-any.whl:
Publisher:
publish.yml on rdslw/llm-tool-brave
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
llm_tool_brave-0.9.1-py3-none-any.whl -
Subject digest:
ae916818bd5244ed14cfa2757dc456c94b334c819b1eef1f87b5d5ab04434601 - Sigstore transparency entry: 1783703165
- Sigstore integration time:
-
Permalink:
rdslw/llm-tool-brave@1c7aff9f120bcbf2e875d419d5133fe05ad3fa7d -
Branch / Tag:
refs/tags/v0.9.1 - Owner: https://github.com/rdslw
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1c7aff9f120bcbf2e875d419d5133fe05ad3fa7d -
Trigger Event:
release
-
Statement type: