

Also from Kynth Studios


Also from Kynth Studios


Also from Kynth Studios
1# packages/sdk/python — Python SDK for the Caveman Cloud gateway23Stdlib-only (`urllib.request`, no third-party deps) Python package. Provides `Cave` (config +4entrypoint), `CaveTool` (tool descriptor), and `ToolSearchResult`. All HTTP calls POST to the5gateway with `x-cave-agent` / `x-cave-workflow` / `x-cave-retention` headers set from `Cave` fields.67## Layout89- `caveman_cloud/__init__.py` — re-exports `Cave`, `CaveTool`, `CompressResult`, `ContextPackItem`, `ContextPackOptions`, `ContextPackResult`, `ToolSearchResult`, …10- `caveman_cloud/core.py` — all implementation: `Cave`, `Trace`, `Provider`, `_Create`, `ToolSearchResult`, `CompressResult`, `ContextPack*`, `CaveTool`, `headers()`11- `tests/test_sdk.py` — pytest tests; mock `urllib.request.urlopen` with `patch()`12- `tests/test_parity.py` — cross-language conformance suite; drives `../../parity/fixtures.json` (shared with sdk-ts). Same fixtures, two languages → a field in one SDK and not the other fails CI.13- `tests/test_runtime_policy.py` — runtime-policy client; drives every section of `../../parity/runtime-policy.fixtures.json` (fetch wire, signature cases, the `guard_cases` fail-closed truth table, assignment vectors with exact float equality — including the weighted `exp-w` vectors that pin the `(1-h)*(w/t)` propensity association — and decision cases). Mirrors the TS `tests/runtime-policy.runtime.mjs`14- `tests/test_trace_continuity.py` — trace/span id minting + which requests carry `x-cave-trace-id` / `x-cave-parent-span-id`; mirrors the TS `tests/trace-continuity.runtime.mjs`15- `pyproject.toml` — distribution name `caveman-sdk` (import package stays `caveman_cloud`), `requires-python = ">=3.13"`, no runtime dependencies1617## Key API surface (`core.py`)1819- `Cave.trace(workflow, tags, *, trace_id=None, span_id=None)` → context manager yielding `Trace`; call `.model["openai"].responses.create(body)` inside. The trace mints `trace_id` (32 lowercase hex) + a root `span_id` (16 lowercase hex) with the exporter's RNG; `trace_id`/`span_id` continue an inbound trace and a value that isn't the exact hex shape is replaced rather than sent. Every provider call and trace-scoped `/sdk/v1/*` call made **through the trace** carries `x-cave-trace-id` + `x-cave-parent-span-id`; providers and SDK calls built directly off the `Cave` carry neither20- `Trace.exporter(service_name=None)` → a per-service memoized `OTelExporter` whose `default_trace_id` is the trace's, so SDK spans and the gateway's request rows join one trace. Runtime-policy decision spans passed a `Trace` use this same caller-reachable default buffer; call `trace.exporter().export()` to ship them. MIRRORS the TS `CaveTrace.exporter`21- `Cave.tools(catalog, *, strategy="all", initial_tool_count=8)` → builder handle with `.strategy`, `.initial` (`list[CaveTool]`), `.search(query, *, max_tools, context, workflow, ranker, session_id)`. `strategy="deferred"` includes every `always_load` tool exactly once, then fills remaining initial slots from non-mandatory tools; a cap below the mandatory count fails locally. `.search()` always hits the gateway with the FULL catalog. MIRRORS the TS `cave.tools({catalog, strategy})`22- `Cave.tool_search(tools, query, *, context, max_tools, workflow, ranker, session_id)` → flat variant: POSTs `[tools, query]` to `/sdk/v1/tool-search`; returns `ToolSearchResult` with `.saved_tokens` / `.reduction_pct` / `.session_id`. Schema-token counters are estimates; `.token_basis` discloses the counter and `.basis` is always `"inferred"`. `ranker` (`"bm25"`|`"embeddings"`) is passed through verbatim — the SDK never computes similarity23- `Cave.prompts.internal_brevity(*, style, preserve_errors_verbatim=False, preserve_code_verbatim=False)` → output-style snippet (`"none"` → `""`); booleans render lowercase to match the TS `cave.prompts.internalBrevity`24- `Cave.compress(payload, *, content_type=None)` → `CompressResult`; POSTs `/sdk/v1/compress`, maps the Engine report. **Byte-safe pass-through** on any transport/parse problem (original input, `ratio=0.0`, no handle); `.token_count_basis` discloses the counter and `basis` is always `"inferred"`. The SDK delegates — it never reimplements a compressor25- `Cave.context.pack(query, items, options)` → `ContextPackResult`; connected-only POST to `/sdk/v1/context/pack`. Lossy selector over caller-owned items, never CCR/ledger; returns exact `deferred_ids`. Transport or malformed-report failure returns all original items with zero inferred savings26- `Trace.expand(source_ref)` — the GET half of `checkpoint()`; `GET /sdk/v1/checkpoints/{ref}/expand` returns the stored `{source_ref, version, messages, checkpoint}`27- `Cave.openai/anthropic/gemini/vertex(upstream_key)` → `Provider` that proxies through gateway; `Provider.raw(path, body)` is the escape hatch (mirrors the TS provider-client `raw`)28- `Cave.bedrock(region, endpoint="runtime")` → no-network first-party route descriptor; Runtime defaults to `/bedrock`, explicit Mantle returns `/bedrock/anthropic`, and `sdk_only=False` mirrors TS `sdkOnly`29- `Trace.tool(name, options, fn)` — calls `fn()` then POSTs a `tool.call` event30- `Trace.page_artifact(value, options)` / `Trace.artifacts.page(value, options)` — send versioned `{value, options, workflow}`; gateway stores only JSON `value`. `artifacts.get(id)` performs authenticated retrieval. `page_artifact` remains backwards-compatible alias.31- `Trace.model["openai"].responses.create(body, *, latency_class=None, tool_session_id=None)` — when `latency_class` is set, sends the `x-cave-async` header (`"true"` unless `"interactive"`); when `tool_session_id` is set, sends `x-cave-tool-session`, mirroring the TS `trace.model.openai.responses.create(body, {cave:{latencyClass, toolSessionId}})`32- `Trace.checkpoint(messages, options)` — POSTs to `/sdk/v1/checkpoints`; the gateway persists it (Valkey) and returns a reversible `source_ref` you can later expand via `GET /sdk/v1/checkpoints/{ref}/expand`33- `Cave.exporter(service_name=None)` → `OTelExporter`; `record_span(...)` maps current GenAI fields to `gen_ai.*`, `export()` POSTs OTLP/JSON to standard `/v1/traces` (headers via `otlp_headers()`; legacy `/otlp/v1/traces` remains server-only compatibility)34- `Cave.retry_loop_breaker(threshold=3)` → `RetryLoopBreaker`; `.record(name, args)` raises `RetryLoopError` after `threshold` consecutive identical tool calls (interrupts a stuck loop). `.guard(name, args, fn)` records then runs `fn`35- `Cave.runtime_policy(*, public_key, auto_refresh_seconds, kill_env, workflow)` → `RuntimePolicyClient`. `refresh()` GETs `/sdk/v1/runtime-policy` with a 30s timeout and a 1 MiB response cap (`oversized_response`; last-known-good stays active); the bundle travels as a signed STRING, Ed25519 verified before parsing, pinned or TOFU. `decide(task_family, unit_key, context, trace)` is **synchronous, local-only, never raises** and returns a `PolicyDecision` (`execute`/`fallback`/`baseline` + `reason`); `kill()` latches baseline locally; `state()` → `RuntimePolicyState`. Holdout is carved first onto the fallback path; assignment is the exported `policy_unit_fraction(*keys)` (byte-for-byte port of Go `shared/platform/sampling.Fraction`, mirrors the TS `policyUnitFraction`; the parity `assignment_vectors` are its authority, including the empty-unit-key vector `decide()` refuses to assign on). Decision spans are observability only — no savings/dollar/`verified` field exists here. MIRRORS the TS `cave.runtimePolicy`36- `Cave.jobs` → reserved `JobsClient` surface. Every method fails locally with `cave_async_jobs_unavailable`; it performs no network request until durable encrypted request storage, credential custody, and a draining worker exist. MIRRORS the TS `Cave.jobs`3738## Conventions3940- Tests use `patch("urllib.request.urlopen", side_effect=fake_urlopen)` — never real network41- Add new gateway endpoints via `Trace._request(path, body)` or `Provider.create(path, body)`42- `headers()` is the single source for all outgoing headers; edit there, nowhere else43- Deferred tool-search session handoff uses request/result `session_id` plus provider header `x-cave-tool-session`; update sdk-ts + parity fixtures with any change44- Run tests: `pytest` from this directory (Python ≥ 3.13 required)4546## Gotchas4748- **No third-party deps** — do not add `requests`, `httpx`, or any library; keep `dependencies = []` in pyproject.toml49- **byte-safe**: SDK sends request bodies to the gateway unmodified; no rewriting. `compress()` delegates to the Engine and passes the original through on any problem50- **context packing is connected-only and intentionally lossy**: it sends item bytes to gateway, never runs in local wrap, and relies on caller retaining every item named by `deferred_ids`. It chooses what enters window; cache-optimal assembly chooses placement51- `sdk-python` and `sdk-ts` mirror the same field names and `/sdk/v1/*` contract — enforced by the shared parity suite (`tests/test_parity.py` + `../../parity/fixtures.json`), not just convention. A divergence is a CI failure. Change one SDK, change both **and** the fixtures5253See ../../../CLAUDE.md (root)54
One repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| JuliusBrussee/cavemanCLAUDE.md · 98k | CLAUDE.md | archgitdo-notagent-behaviour+1 | 73/100 | today | |
| JuliusBrussee/cavemanagents/AGENTS.md · 98k | AGENTS.md | agent-behaviour | 16/100 | today | |
| JuliusBrussee/cavemanagents/CLAUDE.md · 98k | CLAUDE.md | stylearchsecurityagent-behaviour | 64/100 | today | |
| JuliusBrussee/cavemanbrowse/CLAUDE.md · 98k | CLAUDE.md | testarch | 59/100 | today | |
| JuliusBrussee/cavemancacheengine/CLAUDE.md · 98k | CLAUDE.md | testarch | 73/100 | today | |
| JuliusBrussee/cavemanengine/AGENTS.md · 98k | AGENTS.md | stylearch | 66/100 | today | |
| JuliusBrussee/cavemanengine/CLAUDE.md · 98k | CLAUDE.md | stylearch | 58/100 | today | |
| JuliusBrussee/cavemanextension/AGENTS.md · 98k | AGENTS.md | buildteststylearch+1 | 73/100 | today | |
| JuliusBrussee/cavemanextension/CLAUDE.md · 98k | CLAUDE.md | buildteststylearch+1 | 73/100 | today | |
| JuliusBrussee/cavemanintegrations/CLAUDE.md · 98k | CLAUDE.md | stylearch | 55/100 | today | |
| JuliusBrussee/cavemanmcp/AGENTS.md · 98k | AGENTS.md | stylearch | 79/100 | today | |
| JuliusBrussee/cavemanmcp/CLAUDE.md · 98k | CLAUDE.md | stylearch | 79/100 | today | |
| JuliusBrussee/cavemanmem/AGENTS.md · 98k | AGENTS.md | stylearchperformanceagent-behaviour | 67/100 | today | |
| JuliusBrussee/cavemanmem/CLAUDE.md · 98k | CLAUDE.md | stylearchperformanceagent-behaviour | 71/100 | today | |
| JuliusBrussee/cavemanpackages/agent/CLAUDE.md · 98k | CLAUDE.md | archtesting-strategysecuritydependencies+2 | 34/100 | today | |
| JuliusBrussee/cavemanpackages/cli/AGENTS.md · 98k | AGENTS.md | stylearchdependenciesmonorepo | 71/100 | today | |
| JuliusBrussee/cavemanpackages/cli/CLAUDE.md · 98k | CLAUDE.md | stylearchdependenciesmonorepo | 71/100 | today | |
| JuliusBrussee/cavemanpackages/create-caveman-agent/CLAUDE.md · 98k | CLAUDE.md | archdependenciesmonorepoagent-behaviour | 36/100 | today | |
| JuliusBrussee/cavemanpackages/graders/AGENTS.md · 98k | AGENTS.md | teststylearchtypes+3 | 75/100 | today | |
| JuliusBrussee/cavemanpackages/graders/CLAUDE.md · 98k | CLAUDE.md | teststylearchtypes+3 | 75/100 | today |
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| stacklok/toolhiveCLAUDE.md · 2.0k | CLAUDE.md | buildteststylearch+4 | 100/100 | 14 days ago | |
| Adit-Jain-srm/NightmareNetCLAUDE.md · 46 | CLAUDE.md | buildtestlint-formatstyle+6 | 100/100 | 14 days ago | |
| microsoft/playwrightCLAUDE.md · 95k | CLAUDE.md | buildtestlint-formatstyle+7 | 100/100 | 7 days ago | |
| nimbalyst/nimbalystpackages/android/CLAUDE.md · 1.5k | CLAUDE.md | setupbuildstylearch+2 | 100/100 | 14 days ago | |
| dotCMS/corecore-web/CLAUDE.md · 949 | CLAUDE.md | teststylearchtesting-strategy+3 | 100/100 | 14 days ago | |
| tphakala/birdnet-goCLAUDE.md · 1.6k | CLAUDE.md | buildtestlint-formatstyle+8 | 100/100 | today | |
| tyrchen/geektime-bootcamp-aiw7/genslides/backend/CLAUDE.md · 230 | CLAUDE.md | testlint-formatstylearch+6 | 100/100 | 9 days ago | |
| bagisto/bagistoCLAUDE.md · 28k | CLAUDE.md | setupbuildteststyle+5 | 100/100 | 7 days ago |
A badge carrying the measured quality of the strongest agent config file in this repository, out of 100. It reads from this index every time somebody loads your page, so it changes when the measurement changes and there is nothing to keep up to date. Free, no account, and the value is not something you or we can set by hand.
[](https://rulestack.kynth.studio/configs/juliusbrussee-caveman-packages-sdk-python-claude)Would rather not hotlink us? Every badge is also served in shields.io’s endpoint schema, so shields renders the image and your readers never talk to our domain:
Published by Toolproof, the masthead over this index and eight others. The method behind the number is at toolproof.kynth.studio/methodology, and the whole thing is readable as JSON with no key at /api.