qry

A terminal-native, agent-first web search CLI.
Routes queries through swappable adapter binaries and always outputs JSON.

$ qry "what is the latest version of numpy"

[
  {
    "title":   "NumPy 2.0 Release Notes",
    "url":     "https://numpy.org/doc/stable/release/2.0.0-notes.html",
    "snippet": "NumPy 2.0.0 is the first major release since 2006..."
  }
]

Install

Pick your preferred package manager.

$ npm install -g @justestif/qry
$ mise use -g go:github.com/justestif/qry@latest
$ mise reshim

Adapters

Adapters are separate binaries that do the actual searching. Install the ones you want.

Adapter Source API Key
qry-adapter-brave-api Brave Search API Required
qry-adapter-brave-scrape Brave Search (scraping) None
qry-adapter-ddg-scrape DuckDuckGo Lite (scraping) None
qry-adapter-exa Exa AI (via MCP) None
qry-adapter-github GitHub Search API Optional
qry-adapter-searx SearXNG (self-hostable) None
qry-adapter-stackoverflow Stack Exchange API Optional
qry-adapter-wikipedia Wikipedia / MediaWiki API None

Install an adapter the same way:

$ npm install -g @justestif/qry-adapter-ddg-scrape
$ mise use -g go:github.com/justestif/qry/adapters/ddg-scrape@latest
$ mise reshim
Adapters are completely decoupled from qry — they can be written in any language and swapped without changing core. See adapters.md ↗ to build your own.

Configure

Create ~/.config/qry/config.toml. Config is read fresh on every invocation — no restart needed.

[defaults]
  num     = 10    # results to return
  timeout = "5s"  # per-adapter timeout
[routing]
  # "first"  — try adapters in order, stop at first success
  # "merge"  — query all concurrently, deduplicate by URL
  mode     = "first"
  pool     = ["brave-api", "ddg-scrape"]
  fallback = ["brave-scrape"]  # used only in "first" mode
[adapters.brave-api]
  bin     = "~/.local/share/mise/shims/qry-adapter-brave-api"
  timeout = "5s"

  [adapters.brave-api.config]
    api_key = "${BRAVE_API_KEY}"  # expanded from env at runtime

[adapters.ddg-scrape]
  bin = "~/.local/share/mise/shims/qry-adapter-ddg-scrape"
Use ${VAR} syntax in adapter config values — qry expands them from the environment at runtime so secrets never live in the file.

Agent Usage

qry is designed to be composed. Output is always JSON — pipe it directly to agents or jq.

An agent skill is available for one-line install into any supported agent:

$ npx skills add justestif/qry -g -y

Browse and discover skills at skills.sh ↗.


Run qry --agent-info (or -A) to get a JSON description of the tool and your current configuration — useful for agents to orient themselves before making search calls:

$ qry --agent-info

The output includes the tool description, available flags, routing mode explanations, and each configured adapter with its binary path and availability status.

Adapter config maps show ${VAR} template strings rather than resolved values, so secrets are never exposed to agents.

Routing modes

first

Tries adapters in order, returns on first success. Fast — typically only one adapter is invoked per query. Good for most use cases.

merge

Queries all adapters concurrently, deduplicates results by URL. Broader coverage. Partial failure is not an error — results from successful adapters are returned with warnings.

Reference

Full documentation lives on GitHub.

adapters.md ↗

Adapter contract, protocol, and how to build your own.

schema.md ↗

Config file format, request/response shapes, error codes.

architecture.md ↗

How qry works internally — components, routing, data flow.