ADR 0006: The REST API surface is generated, not hand-written¶
Status¶
Accepted, implemented (M4).
Context¶
The anthropic Python SDK exposes 131 distinct endpoint-backed methods
across messages, messages.batches, models, and an extensive beta
namespace (agents, sessions, environments, vaults, memory_stores,
deployments, files, skills, webhooks, and more), plus six local
helpers with no corresponding HTTP endpoint (messages.stream/parse,
beta.messages.stream/parse/tool_runner, beta.webhooks.unwrap).
Research during planning also found that Anthropic's own ant CLI already
covers this entire surface — it's generated from the same Stainless
OpenAPI spec as the Python SDK (identical openapi_spec_hash and
config_hash at the time of research). A hand-written claudeloop api ...
command tree would, at best, duplicate ant, and — because SDK methods get
added with every model/API release — would start silently missing new
methods the moment anyone stopped tracking upstream changes by hand.
Decision¶
claudeloop api ... will be generated by walking anthropic's resource
class tree via introspection (inspect.signature over the cached_property
descriptors under anthropic.resources, not a live client instance — so no
credentials are needed at import time), binding each discovered method to a
Typer command, and gating the whole thing with a CI test that enumerates the
SDK surface and fails the build the moment a method exists in the SDK with
no corresponding generated command.
Consequences¶
- "No gaps" becomes an enforced claim, not an aspirational one. The drift test also asserts the discovered method count against a committed baseline, so removals (an SDK method disappearing) are caught too, not just additions.
- Path and scalar parameters become real typed Typer options; the request
body is accepted as
--json/--json-filewith@pathfile inlining rather than flattening every nestedTypedDictinto individual flags —antreaches the same conclusion independently, using relaxed-YAML structured flags for the same reason. --raw/--streammodifiers select thewith_raw_response/with_streaming_responseSDK variants; list methods get--max-itemsfor auto-pagination;--providerselects among the alternate SDK clients (AnthropicBedrock,AnthropicVertex,AnthropicAWS,AnthropicGoogleCloud,AnthropicFoundry) — the binder must reflect that onlyAnthropicAWS,AnthropicGoogleCloud, andAnthropicFoundrycarry the SDK's full resource tree; the others (AnthropicBedrock,AnthropicBedrockMantle,AnthropicVertex) expose Messages and Beta only, and offering commands that would simply fail for those providers is worse than not generating them.- The six local helpers with no HTTP endpoint are explicitly enumerated in the drift test as either bound to a hand-written command or deliberately exempted, so none of them can be silently forgotten the way a purely automatic surface-diff might miss them.