Python SDK
The Python SDK (agentsecrets) provides a typed, zero-knowledge interface for calling APIs and managing secrets without exposing raw credentials in application memory or agent contexts.
The No
get()Principle: The SDK intentionally contains noget()method. Process memory never holds plaintext secrets. To configure 3rd-party vendor SDKs (OpenAI, Stripe, Anthropic), use Transparent HTTP Interception with secure zero-knowledge placeholders.
Installation
pip install agentsecrets
Client Initialization & Context Managers
The standard and recommended pattern is using a Context Manager (with / async with), which automatically manages HTTP connection pools and ensures graceful session cleanup:
Synchronous Client (AgentSecrets)
from agentsecrets import AgentSecrets # Recommended: Context manager usage with AgentSecrets() as client: response = client.call( "https://api.stripe.com/v1/balance", bearer="STRIPE_KEY" ) print(response.json())
Explicit Client Initialization Options
# Custom workspace and project scope client = AgentSecrets( workspace="Acme Engineering", project="payments-service", environment="production" ) # With declared agent identity or token client = AgentSecrets(agent="billing-processor") client = AgentSecrets(agent_token="agt_ws01hxyz_4kR9mNpQ...") # With Keychain Token reference (Recommended over raw tokens) client = AgentSecrets(agent_token="BILLING-PROCESSOR_TOKEN") # Custom proxy port & timeout client = AgentSecrets(port=8765, timeout=30.0)
Asynchronous Client (AsyncAgentSecrets)
For asyncio, FastAPI, or async agent frameworks, use AsyncAgentSecrets:
import asyncio from agentsecrets import AsyncAgentSecrets async def fetch_balance(): async with AsyncAgentSecrets() as client: response = await client.call( "https://api.stripe.com/v1/balance", bearer="STRIPE_KEY" ) return response.json() asyncio.run(fetch_balance())
Transparent HTTP Client Interception
Transparent Interception allows official third-party SDKs (openai, stripe, anthropic, langchain, llamaindex) to work natively without holding plaintext secrets in memory.
How It Works
When you call agentsecrets.init(), the SDK dynamically hooks into requests.Session.send, httpx.Client.send, and httpx.AsyncClient.send. When an outgoing request contains an AS_SECRET_ placeholder, the interceptor routes the call through the local AgentSecrets proxy, which resolves the real key from the OS Keychain and injects it into the TLS connection.
Loading diagram...
Setup with OpenAI
import openai from agentsecrets import init, credential # 1. Enable interception at application startup init() # 2. Pass zero-knowledge placeholder reference client = openai.OpenAI(api_key=credential.OPENAI_API_KEY) # 3. Call API normally — raw keys never enter Python memory response = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "Explain zero-knowledge security"}] ) print(response.choices[0].message.content)
Setup with Stripe
import stripe from agentsecrets import init, credential init() stripe.api_key = credential.STRIPE_SECRET_KEY # Requests are intercepted, routed through the proxy, and securely authenticated balance = stripe.Balance.retrieve() print(balance)
Making Calls — client.call()
Bearer Token Injection
response = client.call( "https://api.stripe.com/v1/balance", bearer="STRIPE_KEY" )
POST with JSON Body
response = client.call( "https://api.stripe.com/v1/charges", method="POST", bearer="STRIPE_KEY", body={"amount": 2000, "currency": "usd", "source": "tok_visa"} )
Custom Header Injection
response = client.call( "https://api.sendgrid.com/v3/mail/send", method="POST", header={"X-Api-Key": "SENDGRID_KEY"}, body=payload )
Query Parameter Injection
response = client.call( "https://maps.googleapis.com/maps/api/geocode/json", params={"address": "San Francisco, CA"}, query={"key": "GOOGLE_MAPS_KEY"} )
Basic Authentication
response = client.call( "https://jira.example.com/rest/api/2/issue/PROJ-1", basic="JIRA_CREDS" )
The Response Object
client.call() returns a typed Response instance:
response = client.call("https://api.stripe.com/v1/balance", bearer="STRIPE_KEY") response.status_code # int — HTTP status code (e.g. 200) response.body # str — Raw response body response.json() # dict / list — Parsed JSON payload response.headers # dict — Redacted response headers response.redacted # bool — True if proxy scrubbed a credential echo response.duration_ms # int — Total request round-trip time in ms
Spawning Processes — client.spawn()
Inject secrets as environment variables into a child process with real-time output stream masking:
# Synchronous process spawn result = client.spawn(["stripe", "mcp"]) print(result.exit_code) print(result.stdout) # Asynchronous process spawn result = await client.spawn_async(["python", "worker.py"])
Unit Testing with MockAgentSecrets
Test agent workflows offline without a running proxy daemon:
from agentsecrets.testing import MockAgentSecrets from agentsecrets.client import Response mock = MockAgentSecrets() mock.set_response( "https://api.stripe.com/v1/balance", Response(status_code=200, body='{"object": "balance"}', headers={}) ) # Use as a drop-in replacement for AgentSecrets response = mock.call("https://api.stripe.com/v1/balance", bearer="STRIPE_KEY") assert response.json()["object"] == "balance" # Assert on recorded call metadata (no plaintext values exist) assert len(mock.calls) == 1 assert mock.calls[0].url == "https://api.stripe.com/v1/balance" assert mock.calls[0].bearer == "STRIPE_KEY"
Programmatic Agent Identity (agent module)
Manage scoped agent identities and cryptographic tokens programmatically:
from agentsecrets import agent # List registered agents agent_list = agent.list_agents() # Create or fetch an agent my_agent = agent.create("billing-bot", scopes=["proxy_call"]) # Issue a new scoped token token_info = my_agent.issue_token(description="Worker token", expires_in_days=30) print(f"Token ID: {token_info['token_id']}") # Make calls scoped to this agent identity response = my_agent.call( "https://api.stripe.com/v1/charges", method="POST", bearer="STRIPE_KEY", body={"amount": 500} )