{"id":32009927,"url":"https://github.com/thirdkeyai/symbiont-sdk-python","last_synced_at":"2026-04-22T23:00:57.179Z","repository":{"id":306522774,"uuid":"1023917792","full_name":"ThirdKeyAI/symbiont-sdk-python","owner":"ThirdKeyAI","description":"Python DSK for Symbiont DSL and agent framework.","archived":false,"fork":false,"pushed_at":"2026-03-23T23:44:59.000Z","size":156,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-03T00:39:00.137Z","etag":null,"topics":["agent","agents","ai","python","sdk","security","symbiont"],"latest_commit_sha":null,"homepage":"https://symbiont.dev","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ThirdKeyAI.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-07-21T22:56:29.000Z","updated_at":"2026-03-23T19:23:52.000Z","dependencies_parsed_at":"2025-07-26T07:54:29.643Z","dependency_job_id":"433f4645-9072-4831-a0d7-8a3ed8750db9","html_url":"https://github.com/ThirdKeyAI/symbiont-sdk-python","commit_stats":null,"previous_names":["thirdkeyai/symbiont-sdk-python"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/ThirdKeyAI/symbiont-sdk-python","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ThirdKeyAI%2Fsymbiont-sdk-python","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ThirdKeyAI%2Fsymbiont-sdk-python/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ThirdKeyAI%2Fsymbiont-sdk-python/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ThirdKeyAI%2Fsymbiont-sdk-python/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ThirdKeyAI","download_url":"https://codeload.github.com/ThirdKeyAI/symbiont-sdk-python/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ThirdKeyAI%2Fsymbiont-sdk-python/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32158346,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-22T17:06:48.269Z","status":"ssl_error","status_checked_at":"2026-04-22T17:06:19.037Z","response_time":58,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent","agents","ai","python","sdk","security","symbiont"],"created_at":"2025-10-15T20:26:24.127Z","updated_at":"2026-04-22T23:00:57.168Z","avatar_url":"https://github.com/ThirdKeyAI.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Symbiont Python SDK\n\nA Python SDK for interacting with the Symbiont Agent Runtime System, providing a streamlined interface for building AI-powered applications with agent capabilities, tool review workflows, and security analysis.\n\n## Overview\n\nThe Symbiont Python SDK enables developers to integrate with the Symbiont platform, which provides intelligent agent runtime capabilities and comprehensive tool review workflows. This SDK handles authentication, HTTP requests, error handling, and provides typed models for working with Symbiont agents, tool reviews, and related resources.\n\n## Installation\n\n### Install from PyPI\n\n```bash\npip install symbiont-sdk\n```\n\n### Install from Repository (Development)\n\nFor development or to get the latest features:\n\n```bash\ngit clone https://github.com/thirdkeyai/symbiont-sdk-python.git\ncd symbiont-sdk-python\npip install -e .\n```\n\n### Docker\n\nThe SDK is also available as a Docker image from GitHub Container Registry:\n\n```bash\n# Pull the latest image\ndocker pull ghcr.io/thirdkeyai/symbiont-sdk-python:latest\n\n# Or pull a specific version\ndocker pull ghcr.io/thirdkeyai/symbiont-sdk-python:latest\n```\n\n#### Running with Docker\n\n```bash\n# Run interactively with Python REPL\ndocker run -it --rm ghcr.io/thirdkeyai/symbiont-sdk-python:latest\n\n# Run with environment variables\ndocker run -it --rm \\\n  -e SYMBIONT_API_KEY=your_api_key \\\n  -e SYMBIONT_BASE_URL=http://host.docker.internal:8080/api/v1 \\\n  ghcr.io/thirdkeyai/symbiont-sdk-python:latest\n\n# Run a Python script from host\ndocker run --rm \\\n  -v $(pwd):/workspace \\\n  -w /workspace \\\n  -e SYMBIONT_API_KEY=your_api_key \\\n  ghcr.io/thirdkeyai/symbiont-sdk-python:latest \\\n  python your_script.py\n\n# Execute one-liner\ndocker run --rm \\\n  -e SYMBIONT_API_KEY=your_api_key \\\n  ghcr.io/thirdkeyai/symbiont-sdk-python:latest \\\n  python -c \"from symbiont import Client; print(Client().health_check())\"\n```\n\n#### Building Docker Image Locally\n\n```bash\n# Build from source\ngit clone https://github.com/thirdkeyai/symbiont-sdk-python.git\ncd symbiont-sdk-python\ndocker build -t symbiont-sdk:local .\n\n# Run locally built image\ndocker run -it --rm symbiont-sdk:local\n```\n\n## Symbiont Runtime\n\nThe SDK connects to a running Symbiont runtime (default: `http://localhost:8080/api/v1`). Install the runtime using one of the following methods:\n\n### Homebrew\n\n```bash\nbrew tap thirdkeyai/tap \u0026\u0026 brew install symbi\n```\n\n### Install Script\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/thirdkeyai/symbiont/main/scripts/install.sh | bash\n```\n\n### Docker\n\n```bash\ndocker run -d -p 8080:8080 ghcr.io/thirdkeyai/symbiont:latest\n```\n\n### Pre-built Binaries\n\nDownload pre-built binaries from [GitHub Releases](https://github.com/thirdkeyai/symbiont/releases).\n\n\u003e **Note:** Pre-built binaries are tested but considered less reliable than cargo install or Docker.\n\n### From Source\n\n```bash\ncargo install symbiont\n```\n\n## Configuration\n\nThe SDK features a comprehensive configuration system that supports multiple sources including environment variables, configuration files (YAML/JSON), and programmatic configuration. The system provides centralized management with validation and hot-reloading capabilities.\n\n### Configuration Sources\n\n1. **Environment Variables** - Loaded automatically from `.env` files or system environment\n2. **Configuration Files** - YAML or JSON files with structured configuration\n3. **Programmatic Configuration** - Direct configuration objects in your code\n\n### Basic Configuration\n\nCopy the provided `.env.example` file to get started:\n\n```bash\ncp .env.example .env\n```\n\n### Environment Variables\n\nAll configuration options can be set using environment variables with the `SYMBIONT_` prefix:\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `SYMBIONT_API_KEY` | API key for authentication | None |\n| `SYMBIONT_BASE_URL` | Base URL for the Symbiont API | `http://localhost:8080/api/v1` |\n| `SYMBIONT_TIMEOUT` | Request timeout in seconds | `30` |\n| `SYMBIONT_MAX_RETRIES` | Maximum retries for API calls | `3` |\n| `SYMBIONT_AUTH_JWT_SECRET_KEY` | JWT secret key for token validation | None |\n| `SYMBIONT_AUTH_JWT_ALGORITHM` | JWT algorithm | `HS256` |\n| `SYMBIONT_DB_HOST` | Database host | `localhost` |\n| `SYMBIONT_DB_PORT` | Database port | `5432` |\n| `SYMBIONT_VECTOR_HOST` | Vector database host | `localhost` |\n| `SYMBIONT_VECTOR_PORT` | Vector database port | `6333` |\n| `SYMBIONT_LOGGING_LEVEL` | Logging level | `INFO` |\n\n### Configuration File Example\n\nCreate a `config.yml` file for structured configuration:\n\n```yaml\n# API Configuration\napi_key: \"your_api_key_here\"\nbase_url: \"http://localhost:8080/api/v1\"\ntimeout: 30\nmax_retries: 3\n\n# Authentication Configuration\nauth:\n  jwt_secret_key: \"your-jwt-secret-key\"\n  jwt_algorithm: \"HS256\"\n  jwt_expiration_seconds: 3600\n  enable_refresh_tokens: true\n\n# Database Configuration\ndatabase:\n  host: \"localhost\"\n  port: 5432\n  database: \"symbiont\"\n  username: \"user\"\n  password: \"password\"\n\n# Vector Database Configuration\nvector:\n  provider: \"qdrant\"\n  host: \"localhost\"\n  port: 6333\n  collection_name: \"symbiont_vectors\"\n  vector_size: 1536\n  distance_metric: \"cosine\"\n\n# Logging Configuration\nlogging:\n  level: \"INFO\"\n  enable_console: true\n  enable_structured: false\n```\n\n### Programmatic Configuration\n\n```python\nfrom symbiont import ClientConfig, AuthConfig, VectorConfig\n\n# Create configuration programmatically\nconfig = ClientConfig(\n    api_key=\"your_api_key\",\n    base_url=\"http://localhost:8080/api/v1\",\n    auth=AuthConfig(\n        jwt_secret_key=\"your-secret-key\",\n        enable_refresh_tokens=True\n    ),\n    vector=VectorConfig(\n        host=\"localhost\",\n        port=6333,\n        collection_name=\"my_vectors\"\n    )\n)\n\n# Initialize client with configuration\nclient = Client(config=config)\n```\n\n### Configuration Loading Priority\n\nConfiguration values are loaded in the following priority order (highest to lowest):\n\n1. **Explicit parameters** passed to `Client()`\n2. **Environment variables** with `SYMBIONT_` prefix\n3. **Configuration file** values (if specified)\n4. **Default values**\n\n### Using Configuration Manager\n\n```python\nfrom symbiont import ConfigManager\n\n# Load configuration from file\nconfig_manager = ConfigManager()\nconfig = config_manager.load(\"config.yml\")\n\n# Access configuration\nprint(f\"API URL: {config.base_url}\")\nprint(f\"JWT enabled: {config.auth.enable_refresh_tokens}\")\n\n# Reload configuration (hot-reload)\nupdated_config = config_manager.reload()\n```\n\n## Authentication\n\nThe SDK provides a comprehensive authentication system supporting multiple authentication methods including API keys, JWT tokens, and role-based access control (RBAC).\n\n### Authentication Methods\n\n- **API Key Authentication** - Simple bearer token authentication\n- **JWT (JSON Web Tokens)** - Secure token-based authentication with expiration and refresh\n- **Role-Based Access Control** - Granular permissions system with predefined and custom roles\n\n### JWT Authentication\n\nThe SDK includes full JWT support with automatic token refresh and validation:\n\n```python\nfrom symbiont import Client, AuthConfig, ClientConfig\n\n# Configure JWT authentication\nconfig = ClientConfig(\n    auth=AuthConfig(\n        jwt_secret_key=\"your-secret-key\",\n        jwt_algorithm=\"HS256\",\n        jwt_expiration_seconds=3600,\n        enable_refresh_tokens=True\n    )\n)\n\nclient = Client(config=config)\n\n# Authenticate with JWT token\nauth_response = client.authenticate_jwt(\"your-jwt-token\")\nprint(f\"Authenticated user: {auth_response['user_id']}\")\nprint(f\"Roles: {auth_response['roles']}\")\n\n# Get current user roles\nuser_roles = client.get_user_roles()\nprint(f\"Current user roles: {user_roles}\")\n\n# Validate permissions for specific actions\ncan_write = client.validate_permissions(\"write\", \"documents\")\nprint(f\"Can write to documents: {can_write}\")\n\n# Refresh access token\nrefresh_response = client.refresh_token()\nprint(f\"New access token: {refresh_response['access_token']}\")\n```\n\n### Role-Based Access Control\n\nThe authentication system includes a flexible RBAC system with predefined roles:\n\n```python\nfrom symbiont.auth import AuthManager, Role, Permission\n\n# Available permissions\npermissions = [\n    Permission.READ,      # Read access\n    Permission.WRITE,     # Write access\n    Permission.DELETE,    # Delete access\n    Permission.EXECUTE,   # Execute access\n    Permission.ADMIN      # Administrative access\n]\n\n# Predefined roles\n# - admin: Full system access (all permissions)\n# - user: Standard user access (read, write, execute)\n# - readonly: Read-only access\n\n# Create custom role\ncustom_role = Role(\n    name=\"data_analyst\",\n    permissions={Permission.READ, Permission.EXECUTE},\n    description=\"Can read data and execute analysis\"\n)\n\n# Register custom role with AuthManager\nauth_manager = AuthManager(config.auth)\nauth_manager.create_role(custom_role)\n```\n\n### Authentication Configuration\n\nConfigure authentication in your configuration file:\n\n```yaml\nauth:\n  jwt_secret_key: \"your-secret-key-here\"\n  jwt_algorithm: \"HS256\"\n  jwt_expiration_seconds: 3600        # 1 hour\n  jwt_refresh_expiration_seconds: 86400  # 24 hours\n  enable_refresh_tokens: true\n  token_issuer: \"symbiont\"\n  token_audience: \"symbiont-api\"\n  api_key_header: \"Authorization\"\n```\n\nOr using environment variables:\n\n```bash\nSYMBIONT_AUTH_JWT_SECRET_KEY=your-secret-key\nSYMBIONT_AUTH_JWT_ALGORITHM=HS256\nSYMBIONT_AUTH_JWT_EXPIRATION_SECONDS=3600\nSYMBIONT_AUTH_ENABLE_REFRESH_TOKENS=true\n```\n\n## Quick Start\n\n### Basic Client Initialization\n\n```python\nfrom symbiont import Client\n\n# Initialize with environment variables\nclient = Client()\n\n# Or initialize with explicit parameters\nclient = Client(\n    api_key=\"your_api_key\",\n    base_url=\"http://localhost:8080/api/v1\"\n)\n\n# Initialize with configuration object\nfrom symbiont import ClientConfig, AuthConfig\n\nconfig = ClientConfig(\n    api_key=\"your_api_key\",\n    base_url=\"http://localhost:8080/api/v1\",\n    auth=AuthConfig(jwt_secret_key=\"your-secret\")\n)\nclient = Client(config=config)\n```\n\n### System Health Check\n\n```python\nfrom symbiont import Client\n\nclient = Client()\n\n# Check system health\nhealth = client.health_check()\nprint(f\"Status: {health.status}\")\nprint(f\"Uptime: {health.uptime_seconds} seconds\")\nprint(f\"Version: {health.version}\")\n```\n\n## Memory System\n\nThe SDK includes a comprehensive hierarchical memory system that enables agents to store, retrieve, and manage different types of memories across multiple storage backends. The system supports conversation context, episodic memories, semantic knowledge, and automatic memory consolidation.\n\n### Memory Hierarchy\n\nThe memory system organizes information into different levels:\n\n- **Short-term Memory** - Recent interactions with limited capacity and automatic expiration\n- **Long-term Memory** - Persistent important information with high retention\n- **Episodic Memory** - Event-based contextual memories tied to specific experiences\n- **Semantic Memory** - Fact-based knowledge and learned information\n\n### Memory Types\n\n- **Conversation** - Dialog and interaction memories\n- **Fact** - Factual information and knowledge\n- **Experience** - Event-based experiential memories\n- **Context** - Contextual information and metadata\n- **Metadata** - System and operational metadata\n\n### Adding Memories\n\n```python\nfrom symbiont import Client, MemoryStoreRequest\nfrom symbiont.memory import MemoryType, MemoryLevel\n\nclient = Client()\n\n# Add a conversation memory\nconversation_memory = MemoryStoreRequest(\n    content={\n        \"user_message\": \"What's the weather like?\",\n        \"assistant_response\": \"I can help you check the weather. What's your location?\",\n        \"timestamp\": \"2024-01-15T10:30:00Z\"\n    },\n    memory_type=MemoryType.CONVERSATION,\n    memory_level=MemoryLevel.SHORT_TERM,\n    agent_id=\"agent-123\",\n    conversation_id=\"conv-456\",\n    importance_score=0.7\n)\n\nmemory_response = client.add_memory(conversation_memory)\nprint(f\"Memory stored with ID: {memory_response.memory_id}\")\n\n# Add a factual knowledge memory\nfact_memory = MemoryStoreRequest(\n    content={\n        \"fact\": \"The user prefers metric units for temperature\",\n        \"context\": \"User settings and preferences\",\n        \"confidence\": 0.95\n    },\n    memory_type=MemoryType.FACT,\n    memory_level=MemoryLevel.LONG_TERM,\n    agent_id=\"agent-123\",\n    importance_score=0.9\n)\n\nfact_response = client.add_memory(fact_memory)\nprint(f\"Fact stored with ID: {fact_response.memory_id}\")\n```\n\n### Retrieving Memories\n\n```python\nfrom symbiont import MemoryQuery, MemorySearchRequest\n\n# Retrieve a specific memory\nmemory_query = MemoryQuery(\n    memory_id=\"memory-789\",\n    agent_id=\"agent-123\"\n)\n\nmemory = client.get_memory(memory_query)\nprint(f\"Retrieved memory: {memory.content}\")\n\n# Search memories by criteria\nsearch_request = MemorySearchRequest(\n    agent_id=\"agent-123\",\n    memory_types=[MemoryType.CONVERSATION],\n    memory_levels=[MemoryLevel.SHORT_TERM],\n    query_text=\"weather\",\n    limit=10\n)\n\nsearch_results = client.search_memory(search_request)\nprint(f\"Found {len(search_results.memories)} matching memories\")\n\nfor memory in search_results.memories:\n    print(f\"- {memory.content}\")\n    print(f\"  Importance: {memory.importance_score}\")\n```\n\n### Conversation Context\n\n```python\n# Get conversation context with related memories\nconversation_context = client.get_conversation_context(\n    conversation_id=\"conv-456\",\n    agent_id=\"agent-123\"\n)\n\nprint(f\"Conversation: {conversation_context.conversation_id}\")\nprint(f\"Related memories: {len(conversation_context.memories)}\")\nprint(f\"Context summary: {conversation_context.summary}\")\n\n# List all memories for an agent\nagent_memories = client.list_agent_memories(\n    agent_id=\"agent-123\",\n    limit=50\n)\n\nprint(f\"Agent has {len(agent_memories.memories)} total memories\")\n```\n\n### Memory Consolidation\n\nThe memory system automatically consolidates memories to maintain performance and relevance:\n\n```python\n# Manually trigger memory consolidation\nconsolidation_result = client.consolidate_memory(\"agent-123\")\n\nprint(f\"Consolidation results:\")\nprint(f\"- Promoted to long-term: {consolidation_result.promoted_count}\")\nprint(f\"- Archived: {consolidation_result.archived_count}\")\nprint(f\"- Deleted: {consolidation_result.deleted_count}\")\n```\n\n### Storage Backends\n\nThe memory system supports multiple storage backends:\n\n- **In-Memory** - Fast access for development and testing\n- **Redis** - Distributed caching with persistence\n- **PostgreSQL** - Relational database storage (via configuration)\n\nConfigure the storage backend in your configuration:\n\n```yaml\n# In config.yml\ndatabase:\n  host: \"localhost\"\n  port: 5432\n  database: \"symbiont_memory\"\n  username: \"user\"\n  password: \"password\"\n\n# For Redis backend\nmemory:\n  storage_type: \"redis\"\n  redis_url: \"redis://localhost:6379/1\"\n```\n\n## Vector Database (Qdrant Integration)\n\nThe SDK provides comprehensive vector database integration using Qdrant for semantic search, similarity matching, and knowledge management operations.\n\n### Vector Collections\n\n```python\nfrom symbiont import Client, CollectionCreateRequest\n\nclient = Client()\n\n# Create a vector collection\ncollection_request = CollectionCreateRequest(\n    collection_name=\"documents\",\n    vector_size=1536,\n    distance_metric=\"cosine\",\n    description=\"Document embeddings collection\"\n)\n\ncollection_response = client.create_vector_collection(collection_request)\nprint(f\"Created collection: {collection_response.collection_name}\")\n\n# List all collections\ncollections = client.list_vector_collections()\nprint(f\"Available collections: {collections}\")\n\n# Get collection information\ncollection_info = client.get_collection_info(\"documents\")\nprint(f\"Collection size: {collection_info.vectors_count}\")\nprint(f\"Vector dimension: {collection_info.vector_size}\")\n```\n\n### Vector Operations\n\n```python\nfrom symbiont import VectorUpsertRequest, VectorSearchRequest\n\n# Add vectors to collection\nvectors_data = [\n    {\n        \"id\": \"doc-001\",\n        \"vector\": [0.1, 0.2, 0.3, ...],  # 1536-dimensional vector\n        \"payload\": {\n            \"title\": \"Getting Started Guide\",\n            \"content\": \"This guide helps you get started...\",\n            \"category\": \"documentation\"\n        }\n    },\n    {\n        \"id\": \"doc-002\",\n        \"vector\": [0.4, 0.5, 0.6, ...],\n        \"payload\": {\n            \"title\": \"API Reference\",\n            \"content\": \"Complete API documentation...\",\n            \"category\": \"reference\"\n        }\n    }\n]\n\nupsert_request = VectorUpsertRequest(\n    collection_name=\"documents\",\n    vectors=vectors_data\n)\n\nupsert_response = client.add_vectors(upsert_request)\nprint(f\"Added {upsert_response.vectors_count} vectors\")\n\n# Search for similar vectors\nsearch_request = VectorSearchRequest(\n    collection_name=\"documents\",\n    query_vector=[0.15, 0.25, 0.35, ...],  # Query vector\n    limit=5,\n    score_threshold=0.7,\n    filter_conditions={\n        \"category\": \"documentation\"\n    }\n)\n\nsearch_response = client.search_vectors(search_request)\nprint(f\"Found {len(search_response.results)} similar vectors\")\n\nfor result in search_response.results:\n    print(f\"- ID: {result.id}\")\n    print(f\"  Score: {result.similarity_score}\")\n    print(f\"  Title: {result.payload['title']}\")\n```\n\n### Semantic Search\n\n```python\n# Perform semantic search with text queries\nsemantic_search = VectorSearchRequest(\n    collection_name=\"documents\",\n    query_text=\"How to authenticate users\",  # Text will be converted to vector\n    limit=3,\n    score_threshold=0.8\n)\n\nresults = client.search_vectors(semantic_search)\nfor result in results.results:\n    print(f\"Match: {result.payload['title']}\")\n    print(f\"Relevance: {result.similarity_score:.2f}\")\n    print(f\"Content: {result.payload['content'][:100]}...\")\n```\n\n### Vector Management\n\n```python\n# Get specific vectors\nvector_ids = [\"doc-001\", \"doc-002\"]\nretrieved_vectors = client.get_vectors(\"documents\", vector_ids)\n\nfor vector in retrieved_vectors:\n    print(f\"Vector ID: {vector['id']}\")\n    print(f\"Payload: {vector['payload']}\")\n\n# Delete vectors\nclient.delete_vectors(\"documents\", [\"doc-003\", \"doc-004\"])\n\n# Count vectors in collection\nvector_count = client.count_vectors(\"documents\")\nprint(f\"Total vectors: {vector_count}\")\n\n# Delete entire collection\nclient.delete_vector_collection(\"old_collection\")\n```\n\n## AgentPin: Credential Verification\n\nThe SDK integrates with [AgentPin](https://github.com/ThirdKeyAI/agentpin) for domain-anchored cryptographic identity verification of AI agents. AgentPin operations run client-side — no Symbiont Runtime required.\n\n### Key Generation \u0026 Credential Issuance\n\n```python\nfrom symbiont import Client\n\nclient = Client()\n\n# Generate P-256 key pair\nprivate_key, public_key = client.agentpin.generate_key_pair()\nkid = client.agentpin.generate_key_id(public_key)\n\n# Issue an ES256 JWT credential\njwt = client.agentpin.issue_credential(\n    private_key_pem=private_key,\n    kid=kid,\n    issuer=\"example.com\",\n    agent_id=\"data-analyzer\",\n    capabilities=[\"read:data\", \"write:reports\"],\n    ttl_secs=3600,\n)\n```\n\n### Credential Verification\n\n```python\n# Online verification (fetches discovery document automatically)\nresult = client.agentpin.verify_credential(jwt)\nprint(f\"Valid: {result.valid}, Agent: {result.agent_id}\")\n\n# Offline verification with pre-fetched documents\ndiscovery = client.agentpin.fetch_discovery_document(\"example.com\")\noffline_result = client.agentpin.verify_credential_offline(jwt, discovery)\n\n# Trust bundle verification (fully offline, no network)\nbundle = client.agentpin.create_trust_bundle()\nbundle_result = client.agentpin.verify_credential_with_bundle(jwt, bundle)\n```\n\n### Discovery \u0026 Key Pinning\n\n```python\n# Fetch and validate discovery documents\ndoc = client.agentpin.fetch_discovery_document(\"example.com\")\nclient.agentpin.validate_discovery_document(doc, \"example.com\")\n\n# TOFU key pinning\npin_store = client.agentpin.create_pin_store()\n\n# Trust bundle persistence\nclient.agentpin.save_trust_bundle(bundle, \"trust-bundle.json\")\nloaded = client.agentpin.load_trust_bundle(\"trust-bundle.json\")\n\n# JWK utilities\njwk = client.agentpin.pem_to_jwk(public_key, kid)\npem = client.agentpin.jwk_to_pem(jwk)\n```\n\n## API Reference\n### Enhanced Client Methods\n\nThe SDK has been significantly expanded with new client methods organized by functionality:\n\n#### Configuration Management\n\n```python\n# Get current client configuration\nconfig = client.get_configuration()\nprint(f\"Base URL: {config.base_url}\")\n\n# Reload configuration from sources\nclient.reload_configuration()\n\n# Configure client with new settings\nnew_config = ClientConfig(base_url=\"https://new-api.example.com\")\nclient.configure_client(new_config)\n```\n\n#### Authentication \u0026 Authorization\n\n```python\n# JWT authentication\nauth_response = client.authenticate_jwt(\"your-jwt-token\")\nprint(f\"User: {auth_response['user_id']}\")\n\n# Token refresh\nrefresh_response = client.refresh_token()\nprint(f\"New token: {refresh_response['access_token']}\")\n\n# Permission validation\ncan_write = client.validate_permissions(\"write\", \"documents\")\nuser_roles = client.get_user_roles()\n```\n\n#### Memory Management\n\n```python\n# Store memories\nmemory_response = client.add_memory(memory_request)\n\n# Retrieve and search memories\nmemory = client.get_memory(memory_query)\nsearch_results = client.search_memory(search_request)\n\n# Conversation context\ncontext = client.get_conversation_context(\"conv-123\", \"agent-123\")\n\n# Memory consolidation\nconsolidation = client.consolidate_memory(\"agent-123\")\n\n# Agent memory listing\nagent_memories = client.list_agent_memories(\"agent-123\")\n```\n\n#### Vector Database Operations\n\n```python\n# Collection management\ncollection = client.create_vector_collection(collection_request)\ncollections = client.list_vector_collections()\ncollection_info = client.get_collection_info(\"my_collection\")\nclient.delete_vector_collection(\"old_collection\")\n\n# Vector operations\nupsert_response = client.add_vectors(upsert_request)\nvectors = client.get_vectors(\"collection\", [\"id1\", \"id2\"])\nsearch_results = client.search_vectors(search_request)\nclient.delete_vectors(\"collection\", [\"id3\", \"id4\"])\nvector_count = client.count_vectors(\"collection\")\n```\n\n#### HTTP Endpoint Management\n\n```python\n# Create and manage HTTP endpoints\nendpoint = client.create_http_endpoint(endpoint_request)\nendpoints = client.list_http_endpoints()\nendpoint_info = client.get_http_endpoint(\"endpoint-123\")\nupdated_endpoint = client.update_http_endpoint(update_request)\n\n# Endpoint control\nclient.enable_http_endpoint(\"endpoint-123\")\nclient.disable_http_endpoint(\"endpoint-123\") \nclient.delete_http_endpoint(\"endpoint-123\")\n\n# Endpoint metrics\nmetrics = client.get_endpoint_metrics(\"endpoint-123\")\nprint(f\"Request count: {metrics.request_count}\")\nprint(f\"Average response time: {metrics.avg_response_time}ms\")\n```\n\n\n### Agent Management\n\n#### List Agents\n\n```python\n# Get list of all agents\nagents = client.list_agents()\nprint(f\"Found {len(agents)} agents: {agents}\")\n```\n\n#### Get Agent Status\n\n```python\nfrom symbiont import AgentState\n\n# Get specific agent status\nstatus = client.get_agent_status(\"agent-123\")\nprint(f\"Agent {status.agent_id} is {status.state}\")\nprint(f\"Memory usage: {status.resource_usage.memory_bytes} bytes\")\nprint(f\"CPU usage: {status.resource_usage.cpu_percent}%\")\n```\n\n#### Create Agent\n\n```python\nfrom symbiont import Agent\n\n# Create a new agent\nagent_data = Agent(\n    id=\"my-agent\",\n    name=\"My Assistant\",\n    description=\"A helpful AI assistant\",\n    system_prompt=\"You are a helpful assistant.\",\n    tools=[\"web_search\", \"calculator\"],\n    model=\"gpt-4\",\n    temperature=0.7,\n    top_p=0.9,\n    max_tokens=1000\n)\n\nresult = client.create_agent(agent_data)\nprint(f\"Created agent: {result}\")\n```\n\n### Workflow Execution\n\n```python\nfrom symbiont import WorkflowExecutionRequest\n\n# Execute a workflow\nworkflow_request = WorkflowExecutionRequest(\n    workflow_id=\"data-analysis-workflow\",\n    parameters={\n        \"input_data\": \"path/to/data.csv\",\n        \"analysis_type\": \"statistical\"\n    },\n    agent_id=\"agent-123\"  # Optional\n)\n\nresult = client.execute_workflow(workflow_request)\nprint(f\"Workflow result: {result}\")\n```\n\n### Tool Review API\n\nThe Tool Review API provides comprehensive workflows for securely reviewing, analyzing, and signing MCP tools.\n\n#### Submit Tool for Review\n\n```python\nfrom symbiont import (\n    ReviewSessionCreate, Tool, ToolProvider, ToolSchema\n)\n\n# Define a tool for review\ntool = Tool(\n    name=\"example-calculator\",\n    description=\"A simple calculator tool\",\n    schema=ToolSchema(\n        type=\"object\",\n        properties={\n            \"operation\": {\n                \"type\": \"string\",\n                \"enum\": [\"add\", \"subtract\", \"multiply\", \"divide\"]\n            },\n            \"a\": {\"type\": \"number\"},\n            \"b\": {\"type\": \"number\"}\n        },\n        required=[\"operation\", \"a\", \"b\"]\n    ),\n    provider=ToolProvider(\n        name=\"example-provider\",\n        public_key_url=\"https://example.com/pubkey.pem\"\n    )\n)\n\n# Submit for review\nreview_request = ReviewSessionCreate(\n    tool=tool,\n    submitted_by=\"developer@example.com\",\n    priority=\"normal\"\n)\n\nsession = client.submit_tool_for_review(review_request)\nprint(f\"Review session {session.review_id} created with status: {session.status}\")\n```\n\n#### Monitor Review Progress\n\n```python\nfrom symbiont import ReviewStatus\n\n# Get review session details\nsession = client.get_review_session(\"review-123\")\nprint(f\"Review status: {session.status}\")\nprint(f\"Submitted by: {session.submitted_by}\")\n\n# Check if analysis is complete\nif session.state.analysis_id:\n    analysis = client.get_analysis_results(session.state.analysis_id)\n    print(f\"Risk score: {analysis.risk_score}/100\")\n    print(f\"Found {len(analysis.findings)} security findings\")\n    \n    for finding in analysis.findings:\n        print(f\"- {finding.severity.upper()}: {finding.title}\")\n```\n\n#### List Review Sessions\n\n```python\n# List all review sessions with filtering\nsessions = client.list_review_sessions(\n    page=1,\n    limit=10,\n    status=\"pending_review\",\n    author=\"developer@example.com\"\n)\n\nprint(f\"Found {len(sessions.sessions)} sessions\")\nfor session in sessions.sessions:\n    print(f\"- {session.review_id}: {session.tool.name} ({session.status})\")\n```\n\n#### Wait for Review Completion\n\n```python\n# Wait for review to complete (with timeout)\ntry:\n    final_session = client.wait_for_review_completion(\"review-123\", timeout=300)\n    print(f\"Review completed with status: {final_session.status}\")\n    \n    if final_session.status == \"approved\":\n        print(\"Tool approved for signing!\")\n    elif final_session.status == \"rejected\":\n        print(\"Tool rejected. Check review comments.\")\n        \nexcept TimeoutError:\n    print(\"Review did not complete within timeout period\")\n```\n\n#### Submit Human Review Decision\n\n```python\nfrom symbiont import HumanReviewDecision\n\n# Submit reviewer decision\ndecision = HumanReviewDecision(\n    decision=\"approve\",\n    comments=\"Tool looks safe after manual review\",\n    reviewer_id=\"reviewer@example.com\"\n)\n\nresult = client.submit_human_review_decision(\"review-123\", decision)\nprint(f\"Decision submitted: {result}\")\n```\n\n#### Sign Approved Tool\n\n```python\nfrom symbiont import SigningRequest\n\n# Sign an approved tool\nsigning_request = SigningRequest(\n    review_id=\"review-123\",\n    signing_key_id=\"key-456\"\n)\n\nsignature = client.sign_approved_tool(signing_request)\nprint(f\"Tool signed at {signature.signed_at}\")\nprint(f\"Signature: {signature.signature}\")\n\n# Get signed tool information\nsigned_tool = client.get_signed_tool(\"review-123\")\nprint(f\"Signed tool: {signed_tool.tool.name}\")\nprint(f\"Signature algorithm: {signed_tool.signature_algorithm}\")\n```\n\n## Error Handling\n\nThe SDK provides specific exception classes for different types of errors:\n\n```python\nfrom symbiont import (\n    Client, APIError, AuthenticationError, \n    NotFoundError, RateLimitError, SymbiontError\n)\n\nclient = Client()\n\ntry:\n    # Make an API request\n    session = client.get_review_session(\"non-existent-review\")\n    \nexcept AuthenticationError as e:\n    print(f\"Authentication failed: {e}\")\n    print(\"Please check your API key\")\n    \nexcept NotFoundError as e:\n    print(f\"Resource not found: {e}\")\n    print(f\"Response: {e.response_text}\")\n    \nexcept RateLimitError as e:\n    print(f\"Rate limit exceeded: {e}\")\n    print(\"Please wait before making more requests\")\n    \nexcept APIError as e:\n    print(f\"API error (status {e.status_code}): {e}\")\n    print(f\"Response: {e.response_text}\")\n    \nexcept SymbiontError as e:\n    print(f\"SDK error: {e}\")\n    \nexcept Exception as e:\n    print(f\"Unexpected error: {e}\")\n```\n\n### Exception Hierarchy\n\n- `SymbiontError` - Base exception for all SDK errors\n  - `APIError` - Generic API errors (4xx and 5xx status codes)\n  - `AuthenticationError` - 401 Unauthorized responses\n  - `NotFoundError` - 404 Not Found responses\n  - `RateLimitError` - 429 Too Many Requests responses\n\n## Advanced Usage\n\n### Working with Models\n\nAll API responses are automatically converted to typed Pydantic models:\n\n```python\nfrom symbiont import ReviewSession, SecurityFinding, FindingSeverity\n\n# Models provide type safety and validation\nsession = client.get_review_session(\"review-123\")\n\n# Access typed attributes\nsession_id: str = session.review_id\nstatus: ReviewStatus = session.status\nsubmitted_time: datetime = session.submitted_at\n\n# Work with nested models\nif session.state.critical_findings:\n    for finding in session.state.critical_findings:\n        finding_id: str = finding.finding_id\n        severity: FindingSeverity = finding.severity\n        confidence: float = finding.confidence\n```\n\n### Batch Operations\n\n```python\n# Submit multiple tools for review\ntools_to_review = [tool1, tool2, tool3]\nreview_sessions = []\n\nfor tool in tools_to_review:\n    request = ReviewSessionCreate(\n        tool=tool,\n        submitted_by=\"batch@example.com\"\n    )\n    session = client.submit_tool_for_review(request)\n    review_sessions.append(session)\n\nprint(f\"Submitted {len(review_sessions)} tools for review\")\n\n# Monitor all sessions\nfor session in review_sessions:\n    current_status = client.get_review_session(session.review_id)\n    print(f\"Tool {current_status.tool.name}: {current_status.status}\")\n```\n\n## Testing\n\n### Install Development Dependencies\n\n```bash\npip install -r requirements-dev.txt\n```\n\n### Run Tests\n\n```bash\n# Run all tests\npytest\n\n# Run tests with coverage\npytest --cov=symbiont\n\n# Run specific test file\npytest tests/test_client.py\n\n# Run tests with verbose output\npytest -v\n```\n\n### Running Tests in Development\n\n```bash\n# Create a virtual environment (recommended)\npython -m venv venv\nsource venv/bin/activate  # On Windows: venv\\Scripts\\activate\n\n# Install dependencies\npip install -r requirements.txt\npip install -r requirements-dev.txt\n\n# Run tests\npytest\n```\n\n## Requirements\n\n- Python 3.7+\n- requests\n- pydantic\n- python-dotenv\n\n## Reasoning Loop (v1.6.0)\n\nRun autonomous reasoning loops with policy gates, circuit breakers, and knowledge recall:\n\n```python\nfrom symbiont import Client, RunReasoningLoopRequest, LoopConfig\n\nclient = Client()\n\n# Run a reasoning loop\nrequest = RunReasoningLoopRequest(\n    config=LoopConfig(max_iterations=10, timeout_ms=60000),\n    initial_message=\"Analyze the latest sales data and create a report.\",\n)\nresponse = client.reasoning.run_loop(\"agent-1\", request)\n\nprint(f\"Output: {response.result.output}\")\nprint(f\"Iterations: {response.result.iterations}\")\nprint(f\"Termination: {response.result.termination_reason.type}\")\n\n# Check loop status\nstatus = client.reasoning.get_loop_status(\"agent-1\", response.loop_id)\n\n# Read journal entries\njournal = client.reasoning.get_journal_entries(\"agent-1\", limit=50)\n\n# Cedar policy management\nfrom symbiont import CedarPolicy\n\nclient.reasoning.add_cedar_policy(\"agent-1\", CedarPolicy(\n    name=\"deny-file-write\",\n    source='forbid(principal, action == \"tool_call\", resource) when { resource.name == \"write_file\" };',\n    active=True,\n))\npolicies = client.reasoning.list_cedar_policies(\"agent-1\")\n\n# Circuit breaker status\nbreakers = client.reasoning.get_circuit_breaker_status(\"agent-1\")\n\n# Knowledge bridge\nclient.reasoning.store_knowledge(\"agent-1\", \"sales\", \"grew_by\", \"15%\")\nfacts = client.reasoning.recall_knowledge(\"agent-1\", \"sales growth\")\n```\n\n## What's New in v1.10.0\n\n- **HTTP Input LLM invocation models** — Pydantic models for the Symbiont\n  v1.10.0 HTTP Input handler response shapes:\n  `WebhookExecutionStartedResponse` (runtime dispatch),\n  `WebhookCompletedResponse` (on-demand LLM ORGA loop),\n  plus `WebhookToolRun`, `WebhookInvocationRequest`,\n  `WebhookInvocationStatus`, and the `WebhookInvocationResponse` union.\n- **Alignment with Symbiont runtime v1.10.0** — package version bumped to\n  1.10.0. Symbiont v1.9.0 / v1.9.1 added ToolClad v0.4.0 runtime features\n  (session / browser execution modes, HTTP and MCP proxy backends, output\n  parsers, custom types, secrets injection, W3C `traceparent` propagation);\n  existing SDK models remain backward compatible, and `ToolManifestInfo.backend`\n  now accepts `\"http\"`, `\"mcp\"`, `\"session\"`, and `\"browser\"` in addition\n  to previously documented values.\n\n### Previous Releases\n\n#### v1.8.1\n\n- **ToolCladClient** — `list_tools()`, `validate_manifest()`, `test_tool()`, `get_schema()`, `execute_tool()`, `get_tool_info()`, `reload_tools()`\n- **CommunicationPolicyGate client methods** — `list_communication_rules()`, `add_communication_rule()`, `remove_communication_rule()`, `evaluate_communication()`\n- **Agent lifecycle** — `delete_agent()`, `re_execute_agent()`\n- **ORGA-adaptive** — `reasoning.get_tool_profiles()`, `reasoning.get_loop_diagnostics()`\n\n#### v1.6.0\n\n- **Reasoning Loop** — `client.reasoning.run_loop()`, `get_loop_status()`, `cancel_loop()` for autonomous ORGA cycles\n- **Journal System** — `get_journal_entries()`, `compact_journal()` for loop event replay and auditing\n- **Cedar Policies** — `list_cedar_policies()`, `add_cedar_policy()`, `evaluate_cedar_policy()` for action-level governance\n- **Circuit Breakers** — `get_circuit_breaker_status()`, `reset_circuit_breaker()` for tool failure isolation\n- **Knowledge Bridge** — `recall_knowledge()`, `store_knowledge()` for persistent agent memory\n- **Pydantic Models** — Full type coverage for all reasoning types in `symbiont.reasoning`\n\n#### v0.6.0\n\n### Webhook Verification\n\nVerify inbound webhook signatures from GitHub, Stripe, Slack, or custom providers:\n\n```python\nfrom symbiont import WebhookProvider, HmacVerifier, JwtVerifier\n\n# Use a provider preset\nverifier = WebhookProvider.GITHUB.verifier(secret=b\"your-secret\")\nverifier.verify(request.headers, request.body)\n\n# Manual HMAC with prefix stripping\nhmac = HmacVerifier(secret=b\"your-secret\", header_name=\"X-Hub-Signature-256\", prefix=\"sha256=\")\nhmac.verify(headers, body)\n\n# JWT-based verification\njwt_v = JwtVerifier(secret=b\"your-secret\", header_name=\"Authorization\", required_issuer=\"expected-issuer\")\njwt_v.verify(headers, body)\n```\n\nProvider presets: `GITHUB`, `STRIPE`, `SLACK`, `CUSTOM`.\n\n### Markdown Memory Persistence\n\nFile-based agent context that survives restarts:\n\n```python\nfrom symbiont import MarkdownMemoryStore, AgentMemoryContext\n\nstore = MarkdownMemoryStore(\"/data/memory\", retention_days=30)\n\nstore.save_context(\"agent-1\", AgentMemoryContext(\n    agent_id=\"agent-1\",\n    facts=[\"User prefers dark mode\", \"Timezone is UTC-5\"],\n    procedures=[\"Always greet by name\"],\n    learned_patterns=[\"Responds better to bullet points\"],\n    metadata={\"last_session\": \"2026-02-15\"},\n))\n\ncontext = store.load_context(\"agent-1\")\nagents = store.list_agent_contexts()\nstore.compact(\"agent-1\")\nstats = store.get_storage_stats()\n```\n\n### Agent Skills (ClawHavoc Scanning)\n\nScan and load agent skill definitions with security scanning:\n\n```python\nfrom symbiont import SkillScanner, SkillLoader, SkillLoaderConfig\n\n# Scan for security issues (10 built-in ClawHavoc rules)\nscanner = SkillScanner()\nfindings = scanner.scan_content(content, \"SKILL.md\")\n\n# Scan an entire skill directory\nresult = scanner.scan_skill(\"/path/to/skill\")\n\n# Load skills from paths\nloader = SkillLoader(SkillLoaderConfig(\n    load_paths=[\"/skills/verified\", \"/skills/community\"],\n    require_signed=False,\n    scan_enabled=True,\n))\n\nskills = loader.load_all()\nskill = loader.load_skill(\"/path/to/skill\")\n```\n\nDetects: pipe-to-shell, wget-pipe-to-shell, env file references, SOUL.md/memory.md tampering, eval+fetch, base64-decode-exec, rm-rf, chmod-777.\n\n### Metrics Collection \u0026 Export\n\nRuntime metrics retrieval and local export:\n\n```python\nfrom symbiont import FileMetricsExporter, CompositeExporter, MetricsCollector\n\n# Fetch from runtime API\nsnapshot = client.metrics_client.get_metrics_snapshot()\nscheduler = client.metrics_client.get_scheduler_metrics()\nsystem = client.metrics_client.get_system_metrics()\n\n# Export to file (atomic JSON write)\nexporter = FileMetricsExporter(file_path=\"/tmp/metrics.json\")\nexporter.export(snapshot)\n\n# Fan-out to multiple backends\ncomposite = CompositeExporter([exporter, other_exporter])\n\n# Background collection\ncollector = MetricsCollector(composite, interval_seconds=60)\ncollector.start(fetch_fn)\ncollector.stop()\n```\n\n### Optional Dependencies\n\n```bash\npip install symbiont-sdk[skills]   # SchemaPin signature verification\npip install symbiont-sdk[metrics]  # OpenTelemetry export\n```\n\n### Other v0.6.0 Additions\n\n- **HmacVerifier** / **JwtVerifier** — Constant-time signature comparison with case-insensitive header lookup\n- **WebhookProvider** enum — Factory method for provider-specific verifiers\n- **SkillScanner** — 10 built-in ClawHavoc security rules with custom rule support\n- **SkillLoader** — YAML frontmatter parsing, SchemaPin signature detection\n- **FileMetricsExporter** — Atomic JSON writes with parent directory creation\n- **CompositeExporter** — Fan-out with partial failure tolerance\n- **MetricsCollector** — Background threading for periodic export\n- **MetricsClient** — Sub-client for runtime metrics API\n\n## Previous Releases\n\n### v0.5.0 — AgentPin Integration\n\n- `client.agentpin.verify_credential()` — Full 12-step online verification\n- `client.agentpin.verify_credential_offline()` — Offline verification with pre-fetched documents\n- `client.agentpin.verify_credential_with_bundle()` — Trust bundle-based verification\n- `client.agentpin.issue_credential()` — Issue ES256 JWT credentials\n- `client.agentpin.generate_key_pair()` — P-256 key generation\n- Key pinning (TOFU), trust bundle persistence, and JWK utilities\n\n### v0.3.0 — Secrets, MCP, Vector DB, DSL\n\n- Secrets management (Vault, file, environment providers)\n- MCP server management and tool integration\n- Vector database \u0026 RAG with Qdrant\n- Agent DSL compilation and deployment\n- Enhanced system and agent metrics\n\n## License\n\nThis project is licensed under the Apache License 2.0. See the [LICENSE](LICENSE) file for details.\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n### Setting up for Development\n\n1. Fork the repository\n2. Clone your fork locally\n3. Set up development environment:\n\n```bash\ngit clone https://github.com/yourusername/symbiont-sdk-python.git\ncd symbiont-sdk-python\npython -m venv .venv\nsource .venv/bin/activate  # On Windows: .venv\\Scripts\\activate\npip install -r requirements.txt\npip install -r requirements-dev.txt\n```\n\n4. Run tests to ensure everything works:\n\n```bash\npytest\nruff check symbiont/\nbandit -r symbiont/\n```\n\n5. Make your changes and add tests\n6. Submit a pull request\n\n### Release Process\n\nReleases are automated through GitHub Actions:\n\n1. **CI/CD**: Every push/PR triggers testing across Python 3.8-3.12\n2. **Release**: Create a new tag with format `v*.*.*` (e.g., `v0.2.0`) to trigger:\n   - Automated testing\n   - Package building\n   - PyPI publishing\n   - GitHub release creation\n\n#### Setting up PyPI Publishing (Maintainers)\n\nFor repository maintainers, set up these GitHub repository secrets:\n\n- `PYPI_API_TOKEN`: PyPI API token for automated publishing\n\nTo create a PyPI API token:\n1. Go to PyPI Account Settings → API tokens\n2. Create new token with scope for this project\n3. Add to GitHub repository secrets as `PYPI_API_TOKEN`\n\n#### Container Registry Publishing\n\nThe Docker workflow automatically publishes container images to GitHub Container Registry:\n\n- **Latest image**: Published on every push to main branch (`ghcr.io/thirdkeyai/symbiont-sdk-python:latest`)\n- **Version tags**: Published on release tags (`ghcr.io/thirdkeyai/symbiont-sdk-python:v0.2.0`)\n- **Branch tags**: Published for feature branches during development\n\nImages are built for multiple architectures (linux/amd64, linux/arm64) and include:\n- Multi-stage optimized builds for smaller image size\n- Non-root user execution for security\n- Health checks for container monitoring\n- Full SDK functionality with all dependencies\n\nBoth the release workflow (PyPI) and Docker workflow (container registry) will automatically run when a new tag is pushed.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthirdkeyai%2Fsymbiont-sdk-python","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthirdkeyai%2Fsymbiont-sdk-python","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthirdkeyai%2Fsymbiont-sdk-python/lists"}