From d36cd2e602d3f9f5f404bffa6d2691b3c3e26520 Mon Sep 17 00:00:00 2001 From: AJ Frio Date: Fri, 14 Aug 2026 12:51:57 -0600 Subject: [PATCH] Add a read-only search example agents can run after setup. Co-Authored-By: Claude Opus 4.8 Co-authored-by: Cursor --- README.md | 6 ++++ docs/CONVENTIONS.md | 4 ++- examples/test_search.py | 69 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 examples/test_search.py diff --git a/README.md b/README.md index eb1bc7f..020c6b1 100644 --- a/README.md +++ b/README.md @@ -141,6 +141,12 @@ search_result = client.api.search.files("bolt") print(search_result) ``` +A runnable read-only script is in [`examples/test_search.py`](examples/test_search.py): + +```bash +python examples/test_search.py bolt +``` + --- ## API groups diff --git a/docs/CONVENTIONS.md b/docs/CONVENTIONS.md index f36fef7..647f1b2 100644 --- a/docs/CONVENTIONS.md +++ b/docs/CONVENTIONS.md @@ -21,6 +21,7 @@ | `bild/errors.py` | exceptions only; no `requests`, no client import | | `bild/client.py` | transport + resource classes until the split lands | | `tests/test_*.py` | one concern per file | +| `examples/` | runnable scripts (not collected as tests) | | `tools/linters/` | harness rules with remediation text | Do not add `bild/utils.py` dumping grounds. Shared helpers stay next to the @@ -44,4 +45,5 @@ delete files, search). Do not "fix" them to `POST`. - Update `docs/INDEX.md` when adding a doc. - Keep `AGENTS.md` under 130 lines. -- User-facing examples live in `README.md`. +- User-facing snippets live in `README.md`. Runnable scripts live in + `examples/`. diff --git a/examples/test_search.py b/examples/test_search.py new file mode 100644 index 0000000..91cfd21 --- /dev/null +++ b/examples/test_search.py @@ -0,0 +1,69 @@ +"""Read-only search smoke test using the Bild Python SDK. + +Hand this file to an agent that is getting ``Invalid search key``. +That error is a request-body problem, not auth. Do not call ``/search`` +yourself. Use ``client.api.search.files(...)`` so the library sends: + + PUT https://api.getbild.com/search + Authorization: Bearer + Accept: application/json + Content-Type: application/json (set only because there is a JSON body) + + {"search_key": ""} + +Optional query params: ``pageSize`` and ``from``. + +Setup (from the repo root): + + pip install -e . + copy .env.example .env # then put the JWT in BILD_API_KEY + + python examples/test_search.py + python examples/test_search.py bolt +""" + +from __future__ import annotations + +import json +import sys + +from bild import BildAPIError, BildAuthError, BildClient + + +def _print(label: str, value: object) -> None: + print(f"\n=== {label} ===") + print(json.dumps(value, indent=2, default=str)) + + +def main(argv: list[str]) -> int: + search_key = argv[1] if len(argv) > 1 else "bolt" + if not search_key.strip(): + print("search_key must be a non-empty string") + return 2 + + client = BildClient() # reads BILD_API_KEY from the environment or .env + + handshake = client.verify() + _print("BildClient.verify()", handshake) + + result = client.api.search.files(search_key, page_size=5) + _print(f'client.api.search.files("{search_key}", page_size=5)', result) + return 0 + + +if __name__ == "__main__": + try: + raise SystemExit(main(sys.argv)) + except ValueError as exc: + print(f"Setup error: {exc}") + raise SystemExit(2) from exc + except BildAuthError as exc: + print(f"Auth failed ({exc.status_code}): {exc.payload}") + raise SystemExit(1) from exc + except BildAPIError as exc: + print(f"API error ({exc.status_code}): {exc.payload}") + print( + "If the payload says Invalid search key, the body key must be " + "search_key (not query, q, or searchKey). Use this script as-is." + ) + raise SystemExit(1) from exc