Catalog PyPI
PACKAGE EXPLORERView in registry

3tears-search

PyPI

Provider-agnostic web and media search for the 3tears family: contracts, adapters, and the staged pipeline

Versions collected1
Direct dependencies5From release 0.72.0
Last observed20 Oct, 15:38 UTC

README

Version 0.72.0 documentation

Provider-agnostic web and media search for the 3tears family.

The authority for everything in this package is docs/search-spec.md (decisions D1-D28), with requirement IDs (SR-*, G*, P*) defined in docs/search-requirements.md.

Layout

threetears/search/
  contracts/        # the leaf within the leaf -- types, protocols, errors, keys
  adapters/
    searxng.py      # one provider's API, over the injected transport
  call.py           # a query → one candidate set, bounded and negotiated
  bind.py           # prose for a model + the metadata projection
  standalone.py     # bare-httpx transport   [standalone] -- the sanctioned path (D19)
  testing/          # the shared provider-conformance suite + declared doubles

Layer names (Adapter, Call, Bind, …) are module vocabulary and never type names, so a later re-cut of the layers stays cheap.

contracts/ is the lingua franca every layer and every consumer speaks:

  • SearchRequest and the open criteria vocabulary (typed constructors for well-known criteria, namespaced keys for everything else), with per-criterion dispositions (pushdown | local | unsatisfied | ignored-unknown).
  • Candidate -- the carrier-neutral result core: identity, locators, provenance, named provenanced scores (never a single score field, D1), fidelity available/achieved, an optional content slot, and additive facets keyed by the media-contracts vocabulary.
  • Spend -- every resource a call consumed: money (Decimal), wall-clock, call count, weighted provider units, bytes.
  • The typed error taxonomy (SR-J1), every error carrying Spend (SR-E3). Zero results is a success value, not an error (SR-J2).
  • SearchTransport -- the injected transport seam (SR-N1, P9). A thin host-side adapter over threetears.core.http_client.TracedHttpClient satisfies it structurally; this package never imports core.
  • SEARCH_RESULTS_METADATA_KEY and the versioned metadata projection (D13, D22).
  • ProviderCapabilities -- what a provider can express, declared and queryable so a consumer branches before sending rather than after failing (SR-B4), following the 3tears-models capability-metadata pattern.
  • SearchProvider -- the provider seam Call depends on and the conformance suite parametrizes over.
  • Canonical serialization of request/parameter types -- one canonical form consumed by both the D26 replay key and eval run identity (SR-F1).

Using it

import asyncio

from threetears.search.adapters.searxng import SearxngAdapter
from threetears.search.bind import bind_search
from threetears.search.contracts import Criterion, SearchRequest
from threetears.search.standalone import StandaloneTransport   # or your own


async def main() -> None:
    adapter = SearxngAdapter(
        base_url="https://searx.internal.example",   # deployment config, never env
        transport=StandaloneTransport(allow_private_addresses=True),
        provider_instance="searxng-main",
    )
    rendered = await bind_search(
        SearchRequest(query="capybara habitat range", criteria=(Criterion.max_results(5),)),
        provider=adapter,
    )
    print(rendered.content)                                  # prose for a model
    print(rendered.metadata["search_results"]["candidates"])  # structure for a program


asyncio.run(main())

bind_search never raises: a typed failure arrives as a failed RenderedSearch carrying its spend under the same metadata key (D10). Callers that want the exception go through threetears.search.call.search instead.

Budgets and pacing pass through the same entry point: hand bind_search (or search) a budget= implementing BudgetPort, a limiter= such as threetears.search.limiter.InProcessRateLimiter -- construct one per process and share it, or pacing paces nothing -- and the egress= name your transport actually exits by (D8, D20). A budget refusal or pacing denial renders as a failed result like any other typed failure; omitting the ports means no budget is consulted and no pacing applies.

Hosts that already have threetears.core should inject a thin adapter over TracedHttpClient rather than take the [standalone] extra -- it brings timeouts, retry, circuit-breaking and spans for free.

Provider conformance

threetears.search.testing ships the suite every adapter passes -- contract shape, spend on failure, error taxonomy, disposition honesty, zero-results-is-success (SR-O5). It imports no test framework, so a consumer can run it against its own wiring:

from threetears.search.testing import ProviderConformanceCase, ProviderConformanceSuite


class TestMyProviderConformance(ProviderConformanceSuite):
    case = ProviderConformanceCase(...)

Not here yet

aggregate.py, extract.py, select.py, limiter.py and replay.py are later phases of docs/search-spec.md §7. Budget-port consultation and pacing are marked seams inside call.py: the port types are Phase 1 PR 2, and a placeholder protocol would only be a second vocabulary to migrate off.

Import-cleanliness

Importing threetears.search.contracts pulls nothing beyond stdlib, pydantic, and 3tears-media-contracts. Nothing in this package imports threetears.core, threetears.agent.*, langchain, or NATS. Nothing reads environment variables -- the host passes base URLs, secret references, and transport (SR-K1).

standalone.py is the only module that imports httpx, and nothing in the package imports standalone at module level: the extra stays opt-in, and a host that injects its own transport never installs it. Both facts are pinned by tests/test_package_boundaries.py, and the module's path is the D19 widening of the no-bespoke-client norm in tests/enforcement/test_no_bespoke_reuse.py -- a sanctioned transport, with no exemption filed.

Downloads & popularity

67downloads
1-day window · source-reported counts19 Oct 2026
587293.50
2026-08-11: 109 · observed 2026-10-20T15:51:50.2735848Z · period 2026-08-11–2026-08-112026-08-12: 196 · observed 2026-10-20T15:51:50.2735848Z · period 2026-08-12–2026-08-122026-08-13: 174 · observed 2026-10-20T15:51:50.2735848Z · period 2026-08-13–2026-08-132026-08-14: 142 · observed 2026-10-20T15:51:50.2735848Z · period 2026-08-14–2026-08-142026-08-15: 134 · observed 2026-10-20T15:51:50.2735848Z · period 2026-08-15–2026-08-152026-08-16: 66 · observed 2026-10-20T15:51:50.2735848Z · period 2026-08-16–2026-08-162026-08-17: 117 · observed 2026-10-20T15:51:50.2735848Z · period 2026-08-17–2026-08-172026-08-18: 506 · observed 2026-10-20T15:51:50.2735848Z · period 2026-08-18–2026-08-182026-08-19: 94 · observed 2026-10-20T15:51:50.2735848Z · period 2026-08-19–2026-08-192026-08-20: 14 · observed 2026-10-20T15:51:50.2735848Z · period 2026-08-20–2026-08-202026-08-21: 26 · observed 2026-10-20T15:51:50.2735848Z · period 2026-08-21–2026-08-212026-08-22: 19 · observed 2026-10-20T15:51:50.2735848Z · period 2026-08-22–2026-08-222026-08-23: 179 · observed 2026-10-20T15:51:50.2735848Z · period 2026-08-23–2026-08-232026-08-24: 111 · observed 2026-10-20T15:51:50.2735848Z · period 2026-08-24–2026-08-242026-08-25: 176 · observed 2026-10-20T15:51:50.2735848Z · period 2026-08-25–2026-08-252026-08-26: 78 · observed 2026-10-20T15:51:50.2735848Z · period 2026-08-26–2026-08-262026-08-27: 4 · observed 2026-10-20T15:51:50.2735848Z · period 2026-08-27–2026-08-272026-08-28: 36 · observed 2026-10-20T15:51:50.2735848Z · period 2026-08-28–2026-08-282026-08-29: 179 · observed 2026-10-20T15:51:50.2735848Z · period 2026-08-29–2026-08-292026-08-30: 20 · observed 2026-10-20T15:51:50.2735848Z · period 2026-08-30–2026-08-302026-08-31: 149 · observed 2026-10-20T15:51:50.2735848Z · period 2026-08-31–2026-08-312026-09-01: 183 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-01–2026-09-012026-09-02: 118 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-02–2026-09-022026-09-03: 175 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-03–2026-09-032026-09-04: 44 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-04–2026-09-042026-09-05: 120 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-05–2026-09-052026-09-06: 40 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-06–2026-09-062026-09-07: 245 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-07–2026-09-072026-09-08: 66 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-08–2026-09-082026-09-09: 390 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-09–2026-09-092026-09-10: 191 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-10–2026-09-102026-09-11: 132 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-11–2026-09-112026-09-12: 120 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-12–2026-09-122026-09-13: 288 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-13–2026-09-132026-09-14: 468 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-14–2026-09-142026-09-15: 340 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-15–2026-09-152026-09-16: 364 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-16–2026-09-162026-09-17: 445 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-17–2026-09-172026-09-18: 187 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-18–2026-09-182026-09-19: 90 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-19–2026-09-192026-09-20: 217 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-20–2026-09-202026-09-21: 340 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-21–2026-09-212026-09-22: 183 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-22–2026-09-222026-09-23: 335 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-23–2026-09-232026-09-24: 345 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-24–2026-09-242026-09-25: 385 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-25–2026-09-252026-09-26: 350 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-26–2026-09-262026-09-27: 271 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-27–2026-09-272026-09-28: 370 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-28–2026-09-282026-09-29: 306 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-29–2026-09-292026-09-30: 169 · observed 2026-10-20T15:51:50.2735848Z · period 2026-09-30–2026-09-302026-10-01: 62 · observed 2026-10-20T15:51:50.2735848Z · period 2026-10-01–2026-10-012026-10-02: 126 · observed 2026-10-20T15:51:50.2735848Z · period 2026-10-02–2026-10-022026-10-03: 331 · observed 2026-10-20T15:51:50.2735848Z · period 2026-10-03–2026-10-032026-10-04: 587 · observed 2026-10-20T15:51:50.2735848Z · period 2026-10-04–2026-10-042026-10-05: 413 · observed 2026-10-20T15:51:50.2735848Z · period 2026-10-05–2026-10-052026-10-06: 21 · observed 2026-10-20T15:51:50.2735848Z · period 2026-10-06–2026-10-062026-10-07: 53 · observed 2026-10-20T15:51:50.2735848Z · period 2026-10-07–2026-10-072026-10-08: 196 · observed 2026-10-20T15:51:50.2735848Z · period 2026-10-08–2026-10-082026-10-09: 224 · observed 2026-10-20T15:51:50.2735848Z · period 2026-10-09–2026-10-092026-10-10: 139 · observed 2026-10-20T15:51:50.2735848Z · period 2026-10-10–2026-10-102026-10-11: 68 · observed 2026-10-20T15:51:50.2735848Z · period 2026-10-11–2026-10-112026-10-12: 62 · observed 2026-10-20T15:51:50.2735848Z · period 2026-10-12–2026-10-122026-10-13: 270 · observed 2026-10-20T15:51:50.2735848Z · period 2026-10-13–2026-10-132026-10-14: 294 · observed 2026-10-20T15:51:50.2735848Z · period 2026-10-14–2026-10-142026-10-15: 180 · observed 2026-10-20T15:51:50.2735848Z · period 2026-10-15–2026-10-152026-10-16: 259 · observed 2026-10-20T15:51:50.2735848Z · period 2026-10-16–2026-10-162026-10-17: 179 · observed 2026-10-20T15:51:50.2735848Z · period 2026-10-17–2026-10-172026-10-18: 311 · observed 2026-10-20T15:51:50.2735848Z · period 2026-10-18–2026-10-182026-10-19: 67 · observed 2026-10-20T15:51:50.2735848Z · period 2026-10-19–2026-10-19
11 Aug19 Oct

pypistats · 70 observations shown. Missing days are unknown. Source category: overall: without mirrors.

View observed values
Date / source periodValueObserved at
2026-10-19 – 2026-10-19672026-10-20T15:51:50.2735848Z
2026-10-18 – 2026-10-183112026-10-20T15:51:50.2735848Z
2026-10-17 – 2026-10-171792026-10-20T15:51:50.2735848Z
2026-10-16 – 2026-10-162592026-10-20T15:51:50.2735848Z
2026-10-15 – 2026-10-151802026-10-20T15:51:50.2735848Z
2026-10-14 – 2026-10-142942026-10-20T15:51:50.2735848Z
2026-10-13 – 2026-10-132702026-10-20T15:51:50.2735848Z
2026-10-12 – 2026-10-12622026-10-20T15:51:50.2735848Z
2026-10-11 – 2026-10-11682026-10-20T15:51:50.2735848Z
2026-10-10 – 2026-10-101392026-10-20T15:51:50.2735848Z
2026-10-09 – 2026-10-092242026-10-20T15:51:50.2735848Z
2026-10-08 – 2026-10-081962026-10-20T15:51:50.2735848Z
2026-10-07 – 2026-10-07532026-10-20T15:51:50.2735848Z
2026-10-06 – 2026-10-06212026-10-20T15:51:50.2735848Z
2026-10-05 – 2026-10-054132026-10-20T15:51:50.2735848Z
2026-10-04 – 2026-10-045872026-10-20T15:51:50.2735848Z
2026-10-03 – 2026-10-033312026-10-20T15:51:50.2735848Z
2026-10-02 – 2026-10-021262026-10-20T15:51:50.2735848Z
2026-10-01 – 2026-10-01622026-10-20T15:51:50.2735848Z
2026-09-30 – 2026-09-301692026-10-20T15:51:50.2735848Z
2026-09-29 – 2026-09-293062026-10-20T15:51:50.2735848Z
2026-09-28 – 2026-09-283702026-10-20T15:51:50.2735848Z
2026-09-27 – 2026-09-272712026-10-20T15:51:50.2735848Z
2026-09-26 – 2026-09-263502026-10-20T15:51:50.2735848Z
2026-09-25 – 2026-09-253852026-10-20T15:51:50.2735848Z
2026-09-24 – 2026-09-243452026-10-20T15:51:50.2735848Z
2026-09-23 – 2026-09-233352026-10-20T15:51:50.2735848Z
2026-09-22 – 2026-09-221832026-10-20T15:51:50.2735848Z
2026-09-21 – 2026-09-213402026-10-20T15:51:50.2735848Z
2026-09-20 – 2026-09-202172026-10-20T15:51:50.2735848Z
2026-09-19 – 2026-09-19902026-10-20T15:51:50.2735848Z
2026-09-18 – 2026-09-181872026-10-20T15:51:50.2735848Z
2026-09-17 – 2026-09-174452026-10-20T15:51:50.2735848Z
2026-09-16 – 2026-09-163642026-10-20T15:51:50.2735848Z
2026-09-15 – 2026-09-153402026-10-20T15:51:50.2735848Z
2026-09-14 – 2026-09-144682026-10-20T15:51:50.2735848Z
2026-09-13 – 2026-09-132882026-10-20T15:51:50.2735848Z
2026-09-12 – 2026-09-121202026-10-20T15:51:50.2735848Z
2026-09-11 – 2026-09-111322026-10-20T15:51:50.2735848Z
2026-09-10 – 2026-09-101912026-10-20T15:51:50.2735848Z
2026-09-09 – 2026-09-093902026-10-20T15:51:50.2735848Z
2026-09-08 – 2026-09-08662026-10-20T15:51:50.2735848Z
2026-09-07 – 2026-09-072452026-10-20T15:51:50.2735848Z
2026-09-06 – 2026-09-06402026-10-20T15:51:50.2735848Z
2026-09-05 – 2026-09-051202026-10-20T15:51:50.2735848Z
2026-09-04 – 2026-09-04442026-10-20T15:51:50.2735848Z
2026-09-03 – 2026-09-031752026-10-20T15:51:50.2735848Z
2026-09-02 – 2026-09-021182026-10-20T15:51:50.2735848Z
2026-09-01 – 2026-09-011832026-10-20T15:51:50.2735848Z
2026-08-31 – 2026-08-311492026-10-20T15:51:50.2735848Z
2026-08-30 – 2026-08-30202026-10-20T15:51:50.2735848Z
2026-08-29 – 2026-08-291792026-10-20T15:51:50.2735848Z
2026-08-28 – 2026-08-28362026-10-20T15:51:50.2735848Z
2026-08-27 – 2026-08-2742026-10-20T15:51:50.2735848Z
2026-08-26 – 2026-08-26782026-10-20T15:51:50.2735848Z
2026-08-25 – 2026-08-251762026-10-20T15:51:50.2735848Z
2026-08-24 – 2026-08-241112026-10-20T15:51:50.2735848Z
2026-08-23 – 2026-08-231792026-10-20T15:51:50.2735848Z
2026-08-22 – 2026-08-22192026-10-20T15:51:50.2735848Z
2026-08-21 – 2026-08-21262026-10-20T15:51:50.2735848Z
2026-08-20 – 2026-08-20142026-10-20T15:51:50.2735848Z
2026-08-19 – 2026-08-19942026-10-20T15:51:50.2735848Z
2026-08-18 – 2026-08-185062026-10-20T15:51:50.2735848Z
2026-08-17 – 2026-08-171172026-10-20T15:51:50.2735848Z
2026-08-16 – 2026-08-16662026-10-20T15:51:50.2735848Z
2026-08-15 – 2026-08-151342026-10-20T15:51:50.2735848Z
2026-08-14 – 2026-08-141422026-10-20T15:51:50.2735848Z
2026-08-13 – 2026-08-131742026-10-20T15:51:50.2735848Z
2026-08-12 – 2026-08-121962026-10-20T15:51:50.2735848Z
2026-08-11 – 2026-08-111092026-10-20T15:51:50.2735848Z

Versions 1

Collected releases
VersionPublishedDirect dependenciesOpen version
0.72.020 Oct 20265

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Repository

ACCESSIBLE
pacepace/3tears

Shared repository data · GitHub

License detected in repository
MIT
License branch / ref
develop
Last push
20 Oct 2026
Archived
No
Contributor identities
— · partial collection

Public sponsor counts have not been collected. These signals belong to the repository owner.

Downloads & popularity

0count
Gauge · observed snapshots20 Oct 2026
10.50
2026-10-20: 0 · observed 2026-10-20T17:18:19.8928356Z
20 Oct20 Oct

github · 1 observations shown. Missing days are unknown.

View observed values
Date / source periodValueObserved at
2026-10-2002026-10-20T17:18:19.8928356Z

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 15:38 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:0b630cb69dd7345dca6bace5a33618e0e420696410ddf94deab71e064d76a83c