Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 

README.md

ID Wispera Python SDK

Credential governance for AI agents - Python edition.

Installation

pip install id-wispera

With Framework Integrations

# LangChain support
pip install id-wispera[langchain]

# CrewAI support
pip install id-wispera[crewai]

# All integrations
pip install id-wispera[all]

Quick Start

Initialize a Vault

idw-py init

Scan for Credentials

# Scan a directory
idw-py scan /path/to/project

# Scan system locations (OpenClaw format)
idw-py scan --system

Import Credentials

# Scan and import all
idw-py import ./project --all --owner dev@company.com -y

# Import high-confidence only
idw-py import ./project --min-confidence 0.9 --owner dev@company.com

# Import single file
idw-py import .env --owner dev@company.com

Import Options

Option Description
--all Import all detected credentials from scan
--min-confidence <level> Minimum confidence threshold (0-1)
--format <format> Import format (env, json, openclaw)
--owner <owner> Human owner email
--auto-name Auto-generate passport names
-y, --yes Import without confirmation
-p, --path <path> Custom vault path

Manage Passports

# List all passports
idw-py list

# Show passport details
idw-py show <passport-id>

# Revoke a passport
idw-py revoke <passport-id> --reason "Compromised"

Python API

Basic Usage

from id_wispera import Vault, create_passport, list_passports
from id_wispera.types import CreatePassportInput, CredentialType, VisaType, Platform

# Load vault
vault = Vault.load("~/.id-wispera/vault.json", passphrase="your-passphrase")

# Create a passport
passport = create_passport(vault, CreatePassportInput(
    name="openai-prod",
    agent_id="agent-001",
    credential_type=CredentialType.API_KEY,
    credential_value="sk-...",
    visa_type=VisaType.ACCESS,
    platforms=[Platform.OPENAI],
    scope=["chat", "embeddings"],
    human_owner="developer@example.com",
))

# List passports
passports = list_passports(vault, status="active")
for p in passports:
    print(f"{p.name}: {p.status}")

Credential Detection

from id_wispera.detection import detect_credentials, mask_credentials_in_text

# Detect credentials in text
text = "My API key is sk-abc123...xyz789"
results = detect_credentials(text)

for result in results:
    print(f"Found {result.type} at line {result.line}")
    print(f"  Value: {result.value[:10]}...")
    print(f"  Confidence: {result.confidence}")

# Mask credentials for safe logging
safe_text = mask_credentials_in_text(text)
print(safe_text)  # "My API key is [REDACTED]"

Policy Engine

from id_wispera.policy import evaluate_policy, validate_passport

# Evaluate whether a passport is allowed to perform an action
result = evaluate_policy(passport, action="access")
print(f"Allowed: {result.allowed}, Reason: {result.reason}")

# Validate a passport against all configured policies
validation = validate_passport(passport)
print(f"Valid: {validation.valid}, Violations: {validation.violations}")

Delegation Management

from id_wispera.delegation import add_delegation, get_delegation_depth

# Add a delegation hop to a passport
delegated = add_delegation(vault, passport_id, hop, issued_by="admin")
print(f"Delegated passport: {delegated.id}")

# Check delegation chain depth
depth = get_delegation_depth(vault, passport_id)
print(f"Delegation depth: {depth}")

Secure Sharing

from id_wispera.sharing import create_share_link, resolve_share_link

# Create a share link with expiry and view limits
link = create_share_link(vault, passport_id, expires_in=3600, max_views=1)
print(f"Share URL: {link.url}")

# Resolve a share link to retrieve the passport
shared = resolve_share_link(vault, link.token)
print(f"Shared passport: {shared.name}")

Locations Registry

from id_wispera.locations import detect_installed_providers, get_provider

# Detect which credential providers are available on the system
providers = detect_installed_providers()
for p in providers:
    print(f"Provider: {p.name} ({p.provider_type})")

# Get a specific provider by name
provider = get_provider("aws")
print(f"Provider: {provider.name}, Installed: {provider.installed}")

Provisioning

from id_wispera.provisioning import provision_and_create_passport, list_providers

# List available provisioning providers
providers = list_providers()
for p in providers:
    print(f"{p.name}: {p.description}")

# Provision a new credential and create a passport in one step
passport = provision_and_create_passport(vault, request, auth)
print(f"Provisioned: {passport.name} on {passport.platforms}")

Framework Integrations

LangChain

from id_wispera.integrations.langchain import WisperaCredentialProvider
from langchain_openai import ChatOpenAI

# Initialize provider (authenticates via session token or OS keychain automatically)
provider = WisperaCredentialProvider(vault_path="~/.id-wispera")

# Use with LangChain
llm = ChatOpenAI(api_key=provider.get("openai-prod"))

# Or use convenience methods
llm = ChatOpenAI(api_key=provider.get_openai_key())

Deprecated: The passphrase parameter in the WisperaCredentialProvider constructor is deprecated. Authentication is now resolved automatically via IDW_SESSION_TOKEN or OS keychain. Run idw auth login before first use.

CrewAI

from id_wispera.integrations.crewai import WisperaSecretManager, WisperaToolCredentials
from crewai import Agent, Task, Crew

# Initialize secret manager (authenticates via session token or OS keychain)
secrets = WisperaSecretManager()

# Create agent with governed credentials
researcher = Agent(
    role="Research Analyst",
    goal="Research and analyze information",
    llm_config=secrets.get_llm_config("anthropic-research", model="claude-3-5-sonnet-20241022"),
)

# Use tool credentials — retrieve via creds.get() instead of os.environ injection
from crewai_tools import SerperDevTool

creds = WisperaToolCredentials(secrets, "serper")
search_tool = SerperDevTool(api_key=creds.get())

Deprecated: The passphrase parameter in the WisperaSecretManager constructor is deprecated. Authentication is now resolved automatically via IDW_SESSION_TOKEN or OS keychain.

Breaking change: WisperaToolCredentials no longer injects credentials into os.environ. Use creds.get() to retrieve the credential value directly.

OpenAI Agents SDK

from id_wispera.integrations.openai_agents import WisperaOpenAIAgentProvider

provider = WisperaOpenAIAgentProvider()

# Get API key for agent initialization
api_key = provider.get_agent_key("openai-prod")

# Get full agent config (api_key, model, provider)
config = provider.get_agent_config("openai-prod", model="gpt-4")

# Get tool authentication headers
tool_auth = provider.get_tool_auth("serper-api")
# Returns: {"tool": "serper-api", "credential": "...", "header_name": "Authorization", "header_template": "Bearer ..."}

# Scoped handoff credentials
cred = provider.get_handoff_credential("openai-prod", target_agent="research-agent", allowed_scopes=["read"])

# Batch tool credentials
creds = provider.get_tool_credentials({"search": "serper-api", "weather": "weather-api"})

Google A2A Protocol

from id_wispera.integrations.google_a2a import WisperaA2AProvider

provider = WisperaA2AProvider()

# Populate an Agent Card with credentials
creds = provider.get_agent_credentials("my-agent")
# Returns: {"auth_token": "...", "agent_id": "...", "scopes": [...], "expires_at": "..."}

# Validate incoming agent authentication
result = provider.validate_agent_auth(token="...", expected_agent_id="agent-123")
# Returns: {"valid": True, "agent_id": "agent-123"}

# Task-scoped credential access
task_creds = provider.get_task_credentials("task-456", required_scopes=["read"], passport_names=["my-agent"])

Slack

from id_wispera.integrations.slack import WisperaSlackProvider

provider = WisperaSlackProvider()

# Individual tokens
bot_token = provider.get_bot_token("slack-bot")       # xoxb-...
app_token = provider.get_app_token("slack-app")        # xapp-...
user_token = provider.get_user_token("slack-user")     # xoxp-...
webhook_url = provider.get_webhook_url("slack-webhook")

# Typed credential with auto-detection
cred = provider.get_slack_credential("slack-bot")
# Returns: {"value": "xoxb-...", "token_type": "bot", "team_id": "T12345"}

# Socket Mode (bot + app tokens together)
tokens = provider.get_socket_mode_tokens("slack-bot", "slack-app")
# Returns: {"bot_token": "xoxb-...", "app_token": "xapp-..."}

# List all Slack credentials in the vault
names = provider.list_slack_credentials()

Auth Module

The id_wispera.auth module provides the zero-plaintext credential architecture for Python:

from id_wispera.auth import PassphraseProvider, SessionTokenManager, KeychainProvider

# PassphraseProvider — derive vault key from passphrase (interactive login)
pp = PassphraseProvider()
vault_key = pp.derive_key(passphrase)

# KeychainProvider — cache/retrieve vault key from OS keychain
kc = KeychainProvider()
kc.store(vault_key)
cached = kc.retrieve()

# SessionTokenManager — create, validate, revoke scoped session tokens
stm = SessionTokenManager(vault)
token = stm.create(name="ci-deploy", scope=["read", "list"], ttl="24h")
session = stm.validate(token)
stm.revoke(token.id)
tokens = stm.list()
Class Purpose
PassphraseProvider Derive vault key from passphrase (interactive login)
SessionTokenManager Create / validate / revoke / list scoped session tokens
KeychainProvider Cache vault key in the OS keychain for session persistence

Environment Variables

Variable Description Default
IDW_SESSION_TOKEN Scoped session token (recommended for headless/CI)
IDW_VAULT_PATH Vault directory path ~/.id-wispera
IDW_PASSPHRASE Vault passphrase Deprecated -- use idw auth login or IDW_SESSION_TOKEN

Vault Compatibility

The Python SDK uses the same vault format as the TypeScript SDK. Vaults are interoperable:

  • AES-256-GCM encryption
  • Scrypt key derivation (N=16384, r=8, p=1)
  • JSON storage format

Development

# Install in development mode
pip install -e ".[dev]"

# Run tests
pytest

# Type checking
mypy id_wispera

License

MIT