Skip to main content

🧵 CredWeave

Provider-agnostic credential pooling, intelligent scheduling, rate-limit cooldown, and automatic failover for Python.

PyPI version Python Version License: MIT Code style: ruff Checked with mypy Dependencies: Zero

Key Features • Why CredWeave? • Design Philosophy • Quickstart • Architecture • Security • Roadmap • Contributing


📌 Why CredWeave?

Production applications communicating with external services—such as LLM APIs, cloud providers, and third-party SaaS—often start with a single API key in an .env file.

As workload scale increases, systems quickly outgrow single-credential architectures:

  • 🏢 Multiple Accounts & Tenants: Distributing load across organization tiers, departments, or multiple provider accounts.
  • ⏱️ Rate-Limit Throttling: Encountering 429 Too Many Requests spikes requiring automated cooldown windows and upstream Retry-After adherence.
  • 🔀 Failover & High Availability: Automatically routing around revoked tokens, depleted credit quotas, or regional outages without downtime.
  • 🔄 Dynamic Scheduling: Balancing requests fairly using Round-Robin, Weighted distribution, or Least-Recently-Used heuristics.
  • 🔒 Security Risks: Secret values accidentally leaking into APM traces, exception tracebacks, or console logs.

Most teams end up hand-crafting fragile, ad-hoc rotation loops tightly coupled to a specific HTTP client (httpx, requests) or provider SDK (openai, anthropic).

CredWeave solves this once and for all: a clean, reusable, protocol-agnostic credential lifecycle engine for Python with zero external dependencies.


✨ Key Features

Feature Description
🛡️ Secret-Safe by Design Secrets are automatically masked (***) in repr(), str(), and exception messages. Zero accidental leaks in logs.
🔌 Protocol & Client Agnostic Works seamlessly with any HTTP client, gRPC client, or provider SDK (httpx, aiohttp, requests, OpenAI, etc.).
⏳ Intelligent Cooldowns Automatically isolates rate-limited keys with fixed durations or exponential backoff, respecting upstream retry_after.
🔀 Resilient Failover Seamlessly pivots to secondary/backup credential tiers when primary quotas are exhausted or credentials fail.
🔄 Pluggable Scheduling Round-robin, weighted allocation, least-recently-used, and custom selection strategies.
📊 Outcome-Driven Lifecycle Simple lease model where clients report outcomes (success, rate_limited, auth_failed, transient_error).
🪶 Zero Dependencies Built strictly on the Python standard library. Hyper-lightweight and blisteringly fast.
🏗️ Clean Architecture Strict inward dependency rule: pure Domain models, well-defined Application ports, and pluggable Infrastructure.

💡 Core Design Philosophy

🔑 CredWeave manages credentials and their lifecycle. It does not perform network requests itself.

┌─────────────────────────────────────────────────────────────────┐
│                      Your Application / Task                    │
│                                                                 │
│   1. Acquire Lease         2. Make Request     3. Report Result │
└───────────┬───────────────────────┬─────────────────────▲───────┘
            │                       │                     │
            ▼                       ▼                     │
   ┌─────────────────┐     ┌─────────────────┐            │
   │ 🧵 CredWeave    │     │ 🌐 Upstream API │            │
   │ Credential Pool │     │ (OpenAI, Cloud) │            │
   └─────────────────┘     └────────┬────────┘            │
                                    │                     │
                                    └─────────────────────┘

By decoupling credential management from networking, your codebase retains complete control over HTTP clients, connection pools, custom retry policies, and telemetry.


🚀 Quickstart

1. Installation

pip install credweave

(Currently in active development: install from source or editable mode via pip install -e .)

2. Basic Usage

Define credentials, initialize a pool, acquire a lease, and report the execution outcome:

import asyncio
from credweave import Credential, CredentialPool, Outcome

# 1. Define credentials with secret material and arbitrary metadata
credentials = [
    Credential(
        id="openai-prod-team-a",
        secrets={"api_key": "sk-proj-live-mock-key-alpha"},
        metadata={"tier": "primary", "rate_limit_rpm": 5000},
    ),
    Credential(
        id="openai-prod-team-b",
        secrets={"api_key": "sk-proj-live-mock-key-beta"},
        metadata={"tier": "fallback", "rate_limit_rpm": 2000},
    ),
]

# 2. Instantiate a pool
pool = CredentialPool(credentials=credentials)


# 3. Acquire a lease, execute your request, and report the outcome
async def dispatch_request() -> None:
    # Acquire the optimal eligible credential:
    lease = await pool.acquire()

    try:
        # Retrieve secret for network execution
        api_key = lease.credential.get_secret("api_key")

        # >>> Execute with your preferred client (e.g. httpx, openai, etc.) <<<
        # response = await openai_client.chat.completions.create(...)

        # Report successful completion:
        await pool.report(lease, Outcome.success())

    except RateLimitException as exc:
        # Credential is automatically put in cooldown; upstream retry_after respected:
        await pool.report(
            lease,
            Outcome.rate_limited(retry_after=exc.retry_after, reason=str(exc)),
        )

    except AuthenticationException as exc:
        # Permanently isolate compromised or revoked credentials:
        await pool.report(
            lease,
            Outcome.auth_failed(reason="Invalid API Key or Revoked Token"),
        )

🔄 The Lease Lifecycle

CredWeave uses a formal Lease pattern to ensure atomic handling, state tracking, and concurrency safety:

stateDiagram-v2
    [*] --> AVAILABLE: Registered in Pool
    AVAILABLE --> LEASED: pool.acquire()
    
    LEASED --> AVAILABLE: Outcome.success()
    LEASED --> RATE_LIMITED: Outcome.rate_limited()
    LEASED --> COOLDOWN: Outcome.transient_error()
    LEASED --> REVOKED: Outcome.auth_failed()
    LEASED --> UNHEALTHY: Outcome.consecutive_failures_exceeded()

    RATE_LIMITED --> AVAILABLE: retry_after elapsed
    COOLDOWN --> AVAILABLE: cooldown elapsed
    UNHEALTHY --> AVAILABLE: authorize_secret() / reset_credential()
    REVOKED --> AVAILABLE: authorize_secret() after repairing the secret
  1. Acquire: The pool evaluates eligible credentials using the configured SelectionStrategy and yields an active Lease.
  2. Execute: The client performs the desired operation using the credential secrets.
  3. Report: The client returns the Lease along with a standardized Outcome (success, rate_limited, auth_failed, transient_error).
  4. Transition: The state store updates credential state, adjusts backoff timers, or escalates health flags.

Concurrency caps and lease timeouts

pool = CredentialPool(
    [
        Credential("primary", secrets={"api_key": "..."}, metadata={"max_concurrency": 2}),
        Credential("backup", secrets={"api_key": "..."}),
    ],
    max_concurrency_per_credential=5,  # default cap; None (the default) means unlimited
    lease_timeout=60.0,  # unreported leases are reclaimed after 60 s
)

A credential at its cap is skipped (its health is untouched) until a slot frees up, and the cap is enforced atomically in the state store, so it holds across threads, asyncio tasks and pools sharing one store. Leases that are never reported are reclaimed automatically on the next acquire/report, or on demand with pool.reclaim_expired_leases(); a late report of a reclaimed lease raises LeaseExpiredError.


🔌 Credential Sources

Besides in-memory credentials (StaticSource), a pool can load credentials from the environment or a JSON file and pick up rotations while running, with no pool recreation and no background thread. Sources are re-read on every acquire; state (usage, cooldowns, health) stays attached to the stable credential id. A secret that was rotated away from is never re-adopted: a pool still holding an older snapshot gets no leases from it, so it cannot undo a rotation. A never-seen secret is adopted as a rotation only by a pool that is advancing from the secret it last saw. CredWeave has no trustworthy source revisions, so it cannot tell a newer unseen secret from an older one. A pool built over a store that already holds a different secret, or whose last observation was superseded, therefore gets no leases from its unseen secret until you call pool.authorize_secret(credential_id); until then its acquires raise NoCredentialsAvailableError. A rotation never changes a credential's health: a REVOKED or UNHEALTHY credential stays out of rotation until you call pool.authorize_secret(credential_id) (after repairing the secret in the source), or pool.reset_credential(credential_id) to clear its state without a secret check. authorize_secret is also how you roll back: restore the earlier secret in the source, then authorize it.

EnvSource: credentials from environment variables

Configure variable names, never secret values:

from credweave import CredentialPool, EnvCredential, EnvSource

source = EnvSource(
    [
        EnvCredential(
            id="openai-primary",
            secrets={"api_key": "OPENAI_API_KEY_PRIMARY"},  # secret field -> env var name
            optional_secrets={"org_id": "OPENAI_ORG_PRIMARY"},  # omitted when unset
            metadata={"tier": "primary", "max_concurrency": 4},
        ),
        EnvCredential(id="openai-backup", secrets={"api_key": "OPENAI_API_KEY_BACKUP"}),
    ]
)
pool = CredentialPool(source=source)

A required variable that is unset or empty raises CredentialSourceError (naming the variable, never a value). Pass environ={...} to read from an injected mapping instead of os.environ, e.g. in tests.

JsonSource: credentials from a JSON file

{
  "credentials": [
    {
      "id": "primary",
      "secrets": {"api_key": "<your-api-key>"},
      "metadata": {"tier": "primary", "max_concurrency": 2}
    },
    {"id": "backup", "secrets": {"api_key": "<your-backup-api-key>"}}
  ]
}
from credweave import CredentialPool, JsonSource

source = JsonSource("credentials.json")  # raises CredentialSourceError if invalid
pool = CredentialPool(source=source)

lease = pool.acquire_sync()  # always sees the newest valid file contents
...
print(source.reload_status)  # generation, last_error, consecutive_failures
  • Strict schema: top-level credentials list; each entry has a unique non-empty id, a non-empty secrets object of strings, and an optional metadata object. Unknown fields, duplicate keys, wrong types and NaN are rejected, with secret-safe messages that never echo file content.
  • Rotation: replace the file (ideally atomically: write a temp file, then os.replace). A changed secret under the same id is used by future leases, while the credential's history and cooldown are preserved. Added credentials are eligible immediately; removed ones receive no new leases, and their active leases can still be reported. The pool reads the source once when it is constructed, so a source that cannot be read then raises CredentialSourceError instead of starting with an unknown baseline.
  • Last known good: if the file turns malformed, the previous credentials keep being served and source.reload_status / source.refresh() report the error. Only the initial load raises.
  • Cost: one stat per read (tune with JsonSource(path, min_check_interval=1.0)). The async API runs file work off the event loop.

YamlSource is not available yet: it needs a YAML parser, which the zero-dependency standard library does not provide.


🛡️ Security & Defense-in-Depth Guarantees

Handling API keys, bearer tokens, and secrets requires strict security invariants and defense-in-depth:

1. Automatic Secret Masking

Secret dictionary keys are visible for debugging, but secret values are masked as '***' in all representations (__repr__, __str__):

from credweave import Credential

cred = Credential(id="ai-key", secrets={"api_key": "sk-secret-12345"})

print(cred)
# Output: Credential(id='ai-key', secrets={'api_key': '***'}, metadata={})

repr(cred)
# Output: "Credential(id='ai-key', secrets={'api_key': '***'}, metadata={})"

2. Safe Secret Access

Secret values are accessed explicitly via cred.get_secret("key"). Attempting to retrieve a missing key raises a clean SecretAccessError without exposing environment state.

3. Exception & Log Sanitization

Exception classes across CredWeave never format or interpolate raw secret values into error messages. Known secret values and identifiable token patterns are redacted from representations and diagnostics.

4. Deep Immutability

All credential dictionaries, views, and nested metadata structures are deeply frozen and immutable, preventing accidental runtime mutation or tampering.


🏗️ Clean Architecture

CredWeave is engineered strictly following Clean Architecture principles:

src/credweave/
├── domain/                  # Pure enterprise entities & domain rules
│   ├── models.py            # Credential, Lease (Immutable data structures)
│   ├── outcomes.py          # Outcome & OutcomeType
│   ├── enums.py             # CredentialState, OutcomeType
│   └── errors.py            # CredWeave domain exception hierarchy
├── application/             # Use cases & port protocols
│   ├── ports/               # Clock, CredentialSource, SelectionStrategy, StateStore
│   └── services/            # CredentialPool orchestration
├── infrastructure/          # Adapters implementing application ports
│   ├── clocks/              # SystemClock (real-time execution)
│   ├── sources/             # StaticSource, EnvSource, JsonSource, FileReloader
│   └── stores/              # MemoryStateStore
└── __init__.py              # Curated, strictly-typed public API exports

For complete architectural specifications, thread-safety invariants, and design trade-offs, explore our Architecture Guide.


🗺️ Roadmap

CredWeave is evolving through distinct, carefully planned phases—from the initial architectural foundation and secret-safe domain models to intelligent scheduling, distributed state stores, and cloud secret managers.

For a detailed breakdown of release phases and planned capabilities, see the full Roadmap.


🤝 Contributing

We welcome contributions from the community! Whether you are fixing a bug, adding new strategies, improving documentation, or proposing features, please check out our Contributing Guide for development setup, testing workflows, and architectural guidelines.


📄 License

This project is licensed under the terms of the MIT License.

Metadata

Release files for credweave 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for credweave 0.1.0
File Size Uploaded Provenance Actions
credweave-0.1.0.tar.gz 151.3 kB With provenance Details for credweave-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for credweave 0.1.0
File Interpreter ABI Platform Actions
credweave-0.1.0-py3-none-any.whl Python 3 none any Details for credweave-0.1.0-py3-none-any.whl

Total release size: 228.2 kB

Release files / credweave-0.1.0.tar.gz

Download URL credweave-0.1.0.tar.gz
Size 151.3 kB
Tags Source
SHA-256 checksum
How to use checksums
fb1e24b71e3a3d6d5f4963c50f8b0f1d02863d1ded4b59079aa6aba5ef538c0c
BLAKE2b-256 checksum
How to use checksums
06db4cbce167d0cb950d892fa19974e8ad8fb1c0aa746333183cbe548eba1a91
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Release files / credweave-0.1.0-py3-none-any.whl

Download URL credweave-0.1.0-py3-none-any.whl
Size 76.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ced80bc88c3ed7b2787a98aceb6e4b64aa527e1e757c9d1b3ebe509d7db9dcf2
BLAKE2b-256 checksum
How to use checksums
d21d8103538473d9bbf949ce83144efd3772fac6ca5ead4a7392210b4e0a356f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Security for credweave 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for credweave-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page