Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 19 additions & 21 deletions AGENT_SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ PyPI yet). Repo: `https://github.com/AJFrio/Bild-Python.git`.

## What to ask the human

Ask these in the human's language. Do not invent answers.
Ask **only** these two things, in the human's language. Do not invent
answers. Do not add extra setup questions.

### 1. Bild API token (required)

Expand All @@ -30,8 +31,7 @@ Prompt:
> commit it or print it again.

If they do not have a token, stop. Tell them to have an admin issue one in
the Bild app, then come back. Do not guess a token. Do not ask for their
Bild password — this SDK only accepts a JWT.
the Bild app, then come back. Do not guess a token.

### 2. Install location (required if you are not already in this repo)

Expand All @@ -43,12 +43,20 @@ Prompt:

Default clone URL: `https://github.com/AJFrio/Bild-Python.git`

### 3. API host (optional)
## Do not invent a host or auth scheme

Default: `https://api.getbild.com`
The host is always `https://api.getbild.com`. Auth is always a Bearer JWT
personal access token (`BILD_API_KEY` / `token=`).

Only ask if they mention a custom or non-production host. If they give one,
you will pass `base_url=...` into `BildClient`. Otherwise omit it.
Do **not** ask about:

- which host or endpoint to use
- AWS Lambda, staging, or any other URL
- OAuth, passwords, API keys that are not this JWT, or "custom auth"

If the human volunteers a different host or auth method, tell them this
SDK only talks to `https://api.getbild.com` with a Bild JWT, then continue
with the token they paste.

## Install

Expand Down Expand Up @@ -94,9 +102,6 @@ Rules:
- Prefer `.env` over putting the token in the shell, so later `BildClient()`
calls work without the human pasting it again.

If they gave a custom host, you do not need to store it unless they ask;
pass it only when constructing the client.

## Handshake (required)

From the repo root, with the venv active, run this exact code:
Expand All @@ -109,15 +114,8 @@ result = client.verify()
print(result)
```

If they gave a custom host:

```python
client = BildClient(base_url="https://their-host.example")
result = client.verify()
```

`verify()` is read-only. It calls `users.list` and `projects.list` and
returns a dict shaped like:
Do not pass `base_url`. `verify()` is read-only. It calls `users.list` and
`projects.list` and returns a dict shaped like:

```python
{
Expand Down Expand Up @@ -146,8 +144,8 @@ Use this shape. Include the real `result` value. Do not omit it.
| Error | Meaning | What you do |
| --- | --- | --- |
| `ValueError: Missing token` | `.env` not loaded or empty | Fix `.env`, retry `verify()` |
| `BildAuthError` (401/403) | Token invalid, expired, or wrong host | Ask for a new token; do not retry blindly |
| Other `BildAPIError` | Host or API problem | Show `status_code` and `payload`; ask the human |
| `BildAuthError` (401/403) | Token invalid or expired | Ask for a new token; do not retry blindly |
| Other `BildAPIError` | API problem | Show `status_code` and `payload`; ask the human |

Do not declare setup complete without a successful `verify()` return value.

Expand Down
2 changes: 1 addition & 1 deletion ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Each `*API` class holds a `client: BildClient` and only issues HTTP via

## HTTP contract

- Default host: `https://api.getbild.com`
- Host: `https://api.getbild.com`
- Auth: `Authorization: Bearer <token>` on every request
- `Accept: application/json` is set on the session
- `Content-Type` is **not** set on the session. `requests` adds it only when
Expand Down
8 changes: 0 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,6 @@ client = BildClient(token="YOUR_JWT_TOKEN")

`BildClient()` with no arguments reads `BILD_API_KEY`. A missing token raises `ValueError`. Invalid or expired tokens raise `BildAuthError` (HTTP 401/403). Other failed responses raise `BildAPIError`.

Default API host: `https://api.getbild.com`.

## 3) Basic usage

```python
Expand Down Expand Up @@ -162,12 +160,6 @@ These map to the groups in the [Bild External API reference](https://bildexterna

---

## Advanced: custom base URL

```python
client = BildClient(token="YOUR_JWT_TOKEN", base_url="https://api.getbild.com")
```

## Escape hatch for unwrapped endpoints

```python
Expand Down
2 changes: 1 addition & 1 deletion docs/design-docs/http-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ when `json=` is passed to `session.request`.
## URL building

`{base_url}/{path}` with `base_url` stripped of a trailing slash and `path`
stripped of a leading slash. Default `base_url` is `https://api.getbild.com`.
stripped of a leading slash. The host is `https://api.getbild.com`.

## Resolvers

Expand Down
2 changes: 1 addition & 1 deletion docs/references/bild-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Upstream reference (wins on path, method, and payload shape):

https://bildexternalapi.portledocs.com/#/docs/apireference?api_page=introduction&product_version=77

Default host used by this SDK: `https://api.getbild.com`.
Host used by this SDK: `https://api.getbild.com`.

When the reference and this client disagree, change the client and tests
first, then the README examples.
10 changes: 10 additions & 0 deletions tests/test_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ def test_architecture_describes_layers(self):
self.assertIn("bild/errors.py", text)
self.assertIn("Content-Type", text)

def test_agent_setup_does_not_invite_alternate_host_or_auth(self):
text = (ROOT / "AGENT_SETUP.md").read_text(encoding="utf-8")
lowered = text.lower()
self.assertIn("https://api.getbild.com", text)
self.assertIn("jwt", lowered)
self.assertIn("do not invent", lowered)
self.assertIn("ask about", lowered)
for banned in ("custom host", "non-production", "their-host"):
self.assertNotIn(banned, lowered)


if __name__ == "__main__":
unittest.main()
Loading