@@ -6,32 +6,32 @@ Guidance for AI agents (Claude Code, etc.) working in this repository.
66
77` httpware ` is a thin, opinionated wrapper around ` httpx2 ` with sync and async clients for building
88resilient service clients; [ ` CONTEXT.md ` ] ( CONTEXT.md ) opens with what it does and owns the
9- vocabulary — read it before naming a concept in code, a test name, or an issue title. It ships
9+ vocabulary. Read it before naming a concept in code, a test name, or an issue title. It ships
1010under the ` modern-python ` org.
1111
1212## Commands
1313
14- ` just ` (task runner) and ` uv ` (package manager). The [ ` justfile ` ] ( justfile ) is the source of truth —
15- ` just --list ` , or read it. The one thing it does not say: ` just docs-build ` runs ` mkdocs --strict `
14+ ` just ` (task runner) and ` uv ` (package manager). The [ ` justfile ` ] ( justfile ) is the source of truth:
15+ run ` just --list ` , or read it. The one thing it does not say: ` just docs-build ` runs ` mkdocs --strict `
1616over the site only, and ` docs/adr/ ` and ` docs/agents/ ` are excluded from it (` exclude_docs ` in
1717` mkdocs.yml ` ) because they are read on GitHub rather than published. Their links are covered
1818instead by the ` links ` job in ` .github/workflows/_checks.yml ` , which runs lychee ` --offline ` over
1919every ` *.md ` in the repo.
2020
2121## Architecture
2222
23- ` httpx2 ` is public surface, not an abstraction to hide : ` httpx2.Request ` and ` httpx2.Response ` are
24- re-exported as-is. Three protocol seams — client ↔ middleware chain, client ↔ decoder list, and
25- httpware ↔ optional extras — are defined in ` CONTEXT.md ` and named ** A** , ** B** and ** C** in the
23+ ` httpx2 ` is part of the public surface : ` httpx2.Request ` and ` httpx2.Response ` are
24+ re-exported as-is. Three protocol seams ( client ↔ middleware chain, client ↔ decoder list, and
25+ httpware ↔ optional extras) are defined in ` CONTEXT.md ` and named ** A** , ** B** and ** C** in the
2626module docstrings that implement them. Never cross a seam except through its protocol.
2727
2828### Key files
2929
3030Every module under ` src/httpware/ ` is named for what it does; read it. What a single-file read will
3131** not** tell you:
3232
33- - ` client.py ` holds ** both worlds** — ` Client ` and ` AsyncClient ` — and they are hand-maintained at
34- parity, not generated . A feature added to one must be mirrored to the other;
33+ - ` client.py ` holds ** both worlds** , ` Client ` and ` AsyncClient ` , hand-maintained at parity;
34+ nothing generates one from the other . A feature added to one must be mirrored to the other;
3535 ` tests/test_client_parity.py ` says why, and names the sole exception (` AsyncTimeout ` has no sync
3636 sibling).
3737- ` errors.py ` owns the tree and both construction rules. Status-keyed ` StatusError ` subclasses take
@@ -54,15 +54,15 @@ Every module under `src/httpware/` is named for what it does; read it. What a si
5454 ` RetryBudget ` , ` _backoff ` , ` _event_loop_guard ` ) written once and driven by both worlds. New
5555 resilience logic goes in a shared object, not into each world's shell.
5656
57- ** House invariants, review-only** — nothing in CI catches these: no ` httpx2._ ` private API (ruff
57+ ** House invariants, review-only. ** Nothing in CI catches these: no ` httpx2._ ` private API (ruff
5858` SLF001 ` flags private * attribute* access but not a used private * import* ); no
59- ` from __future__ import annotations ` (3.11+ floor); no global logging config —
60- ` logging.getLogger("httpware") ` and namespaced children only.
59+ ` from __future__ import annotations ` (3.11+ floor); no global logging config
60+ ( ` logging.getLogger("httpware") ` and namespaced children only) .
6161
6262### Testing patterns
6363
64- Transport mocking is ` httpx2.MockTransport ` passed as ` transport= ` , never ` respx ` — ` respx `
65- targets ` httpx ` , not ` httpx2 ` , and patches its internals. Concurrency-sensitive components carry
64+ Transport mocking is ` httpx2.MockTransport ` passed as ` transport= ` , never ` respx ` , which
65+ targets ` httpx ` rather than ` httpx2 ` and patches its internals. Concurrency-sensitive components carry
6666Hypothesis property tests in ` test_*_props.py ` , and ` stress ` -marked tests drive real thread
6767parallelism: they run under the GIL for coverage, but the proof comes from the free-threaded
6868` 3.14t ` CI job.
@@ -78,10 +78,10 @@ description, and PyPI does not rewrite relative links, so a relative one 404s on
7878- Design principle: thin wrapper, small public surface. ` httpware.__all__ ` is checked against an
7979 explicit expected set in ` tests/test_public_api.py ` , so a symbol cannot appear unnoticed
8080- ` Http ` is two letters in a class name (` AsyncClient ` , not ` ASYNCClient ` ); no ` a ` prefix on async
81- methods, matching ` httpx2 ` — ` aclose() ` is the sole exception
81+ methods, matching ` httpx2 ` ; ` aclose() ` is the sole exception
8282- Docstrings: public API documents the contract; internal helpers get a one-line contract, plus at
83- most 1–2 lines for a genuinely non-obvious constraint. Never narrate implementation or justify
84- code to a reviewer — cross-file rationale lives in an invariant test's docstring
83+ most one or two lines for a non-obvious constraint. Never narrate implementation or justify
84+ code to a reviewer; cross-file rationale lives in an invariant test's docstring
8585
8686## Agent skills
8787
0 commit comments