ADR-0002 — Python + uv; stdlib urllib and argparse; textual the only runtime dep
Context and Problem Statement
The tool needs three outbound HTTP calls (usage GET, refresh POST, profile GET), an argparse-class CLI now and a TUI later, on Linux only. The dependency choice sets the supply-chain surface for a program that handles OAuth credentials.
Decision Drivers
- Minimal supply-chain surface: every runtime dep is audit surface on a credential-handling tool.
- The three endpoints need nothing beyond GET/POST + JSON + headers; stdlib
urllibcovers all of it (proven in production:src/claude_acc_manager/usage/infrastructure/http_transport.pyservinganthropic_oauth.py). - Matches the project's AGENTS.md conventions and keeps the venv reproducible via
uv.lockpins.
Considered Options
- httpx / requests
- stdlib
urllibbehindHttpTransportPort - click / typer
- stdlib
argparse - rich
textual(pinned)
Decision Outcome
Chosen option: "stdlib urllib + stdlib argparse + textual (pinned)", because the three endpoints need nothing beyond GET/POST + JSON + headers and the verb set is small: minimal supply chain on a credential-handling tool.
Python ≥3.12 managed by uv. Runtime dependency set is exactly textual. HTTP is stdlib urllib behind HttpTransportPort; CLI is stdlib argparse in a transport-only cli.py (ADR-0013).
Consequences
Any future need for real HTTP features (HTTP/2, pooling, proxies) must be argued against adding the first networking dep; the thin HttpTransportPort seam is where that swap would land without touching use cases. The textual pin is the only runtime package deptry/uv.lock ever carries; keep it that way.
Pros and Cons of the Options
| Option | Pro | Con |
|---|---|---|
| httpx / requests | Nicer API, connection pooling | +1 permanent dep for three calls that don't need it |
stdlib urllib behind HttpTransportPort |
Zero deps, injectable seam for hermetic tests | Verbosity lives in our thin wrapper |
| click / typer | Decorators, less boilerplate | +1 dep; argparse suffices for a small verb set |
stdlib argparse |
Zero deps, explicit | Manual subcommand wiring |
| rich | Mature TUI primitives | Overlaps textual; two UI deps |
textual (pinned) |
Full TUI framework, pilot-testable headless (TERM=dumb) |
The one runtime dep we carry |
More Information
- Amended:
rich>=14.2,<16joinedtextualas a runtime dep for the human-output layer;cli/human.pybuilds on it directly. The supply-chain argument is unchanged (stdlib HTTP/CLI, UI deps only); the "single runtime dep" phrasing above is the decision as originally recorded. The floor is Python ≥3.11 perpyproject.toml.