Skip to content
Merged
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
53 changes: 26 additions & 27 deletions .agents/project.md
Original file line number Diff line number Diff line change
@@ -1,45 +1,44 @@
# Project profile

<!--
A skeleton from the engineering-assets hub: fill it in for this repository.
Once you edit it, the file is this repository's own and the hub never changes
it again. Agents read it before every task (AGENTS.md), so keep it short and
factual, and delete the hints you have answered. Until it is filled in, agents
find these facts in the repository instead, and say where they found them.
-->

## About

- What this repository is, in one sentence:
- Who uses it:
- Language, version and main frameworks:
- Where the documentation lives:
- What this repository is: `clientwright`, a Python library that runs one resilience and observability core (retries, circuit breaking, deadlines, owned redirects, telemetry) under the public API of popular HTTP clients, published on PyPI. `build()` and `build_sync()` return the HTTP library's own client, such as a genuine `httpx.AsyncClient`, not a wrapper.
- Who uses it: services that call HTTP upstreams through httpx, httpx2, aiohttp, requests or urllib3, and authors of third-party adapters (`register_adapter`).
- Language, version and main frameworks: Python 3.12 and newer, no runtime dependencies; the core in `clientwright/core/` uses the standard library only. Each HTTP library is an optional extra with its adapter in `clientwright/adapters/`: `httpx`, `httpx2`, `aiohttp`, `requests`, `urllib3`. The extras `metrics` (prometheus-client) and `tracing` (OpenTelemetry API), both in `observability`, back `clientwright/adapters/observability/`; `deadline` (deadline-budget), `dishka`, `settings` (Pydantic) and `servicewright` back `clientwright/contrib/`; `all` installs every extra.
- Where the documentation lives: https://bedrock-python.github.io/clientwright/, built with Zensical from `docs/` (`zensical.toml`). `docs/agents.md` is the one-page reference for coding assistants.

## Commands

| Task | Command |
|---|---|
| Install dependencies | |
| Format | |
| Lint and type-check | |
| Test | |
| Run locally | |
| Stop the local run | |
| Install dependencies | `uv sync --group dev --all-extras` (CONTRIBUTING.md, CI). `make install` runs `uv sync --group dev` without the extras: the tests that need an SDK are then skipped, and `make test` fails its coverage threshold. |
| Format | `make fmt`: `uv run ruff format .`, then `uv run ruff check --fix .` |
| Lint and type-check | `make check`: `uv run ruff check .`, `uv run ruff format --check .`, `uv run mypy clientwright`, `uv run lint-imports` (the import-linter contracts in `pyproject.toml`). CI's lint job runs the same four. |
| Test | `make test`: the whole suite, `uv run pytest --cov=clientwright --cov-fail-under=97`. Narrower: `make test-unit` (`uv run pytest -m unit`) and `make test-integration` (`uv run pytest -m integration`). CI runs `uv run pytest -m unit --cov=clientwright --cov-fail-under=90` on Python 3.12 and 3.13, `uv run pytest -m integration`, the unit tests with no extra installed (`uv sync --group test`), and the requests and urllib3 tests with only those two extras. |
| Run locally | A library: nothing to run. The docs: `make docs-serve`. |
| Stop the local run | Ctrl+C in the terminal of `make docs-serve`. |

## Conventions

- Default branch:
- Issue tracker, and how commits and pull requests refer to an issue (for example `#123` or `ACME-123`):
- Branch names (for example `fix/123-short-description`):
- Commit messages (for example Conventional Commits):
- Language of pull request titles and descriptions:
- Where specs and design notes go:
- Default branch: `master`. Changes reach it only through pull requests (a repository ruleset), and the required check is `All checks passed`, the last job of `ci.yml`. The pre-commit hook `no-commit-to-branch` refuses local commits to it.
- Issue tracker: GitHub Issues of this repository; refer to an issue as `#123`, and close it from the pull request with `Closes #123`.
- Branch names: `<type>/<short-description>`, such as `feat/my-feature` (CONTRIBUTING.md) or `fix/settings-converter-nested`.
- Commit messages: Conventional Commits, enforced by the `conventional-pre-commit` hook (`uv run pre-commit install --hook-type pre-commit --hook-type commit-msg`). Pull requests are squash-merged, and release-please reads the squash commit, whose title defaults to the commit's subject for a one-commit pull request and to the pull request's title otherwise: keep both Conventional Commits.
- Language of pull request titles and descriptions: English.
- Where specs and design notes go: the problem in a GitHub issue; the design, the alternatives rejected and the verification in the description of the pull request that closes it. The repository has no place for them.

## Boundaries

- Paths agents must not edit (generated code, vendored code, applied migrations):
- Systems and data agents must never touch:
- `CHANGELOG.md` is generated by release-please: never edit it by hand, and never add an `## [Unreleased]` section. `docs/changelog.md` is a copy of it made for the docs build and ignored by git.
- The version lives in `clientwright/__version__.py`, on the line marked `# x-release-please-version`, and in `.release-please-manifest.json`; release-please bumps both. Never change them by hand.
- `docs/agents.md` is part of the public API: it changes in the same pull request as the API (CONTRIBUTING.md, "The agents page").
- `clientwright/core/` never imports `clientwright/adapters/` or any third-party package, and the adapters never import each other; `clientwright/adapters/_httpx_shared.py` is the one module httpx and httpx2 share. The import-linter contracts in `pyproject.toml` enforce this in `make check` and CI.
- Files from the engineering-assets hub (`AGENTS.md` explains how it works) include the copy-page files (`docs/assets/javascripts/copy-page.js`, `docs/assets/stylesheets/copy-page.css`, `overrides/main.html`, `scripts/emit_markdown.py`), `.github/workflows/docs.yml`, `.github/workflows/release-please.yml`, `.github/dependabot.yml`, `.editorconfig` and `CODE_OF_CONDUCT.md`. Change them in the hub; a change here makes the file this repository's own.
- Never publish to PyPI or create a release by hand: release-please creates the release, and `publish.yml` publishes it.

## Notes

Anything else an agent needs: the architecture in a few lines, known pitfalls, how to get test data.
- Releases: release-please opens its pull request with the workflow's own token, so CI does not start on it. Close and reopen the release pull request to run CI, then merge it; `publish.yml` publishes to PyPI when the Release Please run on `master` completes and a `clientwright-v*` tag points at its commit. Only `feat`, `fix`, `perf` and `revert` commits appear in the changelog.
- Tests: `tests/conftest.py` marks each test by its directory (`tests/unit/` gets `unit`, `tests/integration/` `integration`, `tests/live/` `live`; `--strict-markers`), so a new test goes in the directory of its kind. No Docker: the integration tests start an in-process HTTP origin (`clientwright.core.testing.OriginServer`). `tests/live/` calls real endpoints on the internet and is skipped without `--live` (`make test-live`; `CLIENTWRIGHT_LIVE_HTTPBIN` points it at another httpbin); CI runs it only on a manual dispatch.
- A test module imports an SDK only through `pytest.importorskip` (`tests/unit/test_sdk_imports_are_guarded.py` checks this), so the suite also runs without extras. Every `python` block in `docs/` must parse and import only names that exist (`tests/unit/test_docs_snippets.py`).
- Code style (CONTRIBUTING.md): type hints on every function, tests included; Google-style docstrings on the public API only; lines up to 120 characters; double quotes; comments only for a non-obvious why.
Loading