Get your first secure agent running in minutes.
- Python 3.10 or higher
- Docker and Docker Compose (for local development)
- Basic understanding of async/await in Python
pip install agentweaveFor local development, you'll need SPIRE and OPA running:
# Clone the repository
git clone https://github.com/aj-geddes/agentweave
cd agentweave
# Start SPIRE Server, SPIRE Agent, and OPA
docker-compose up -d
# Verify services are running
docker-compose psThis sets up:
- SPIRE Server (identity provider)
- SPIRE Agent (workload API)
- OPA (policy engine)
Create my_agent.py:
from agentweave import SecureAgent, capability
class HelloAgent(SecureAgent):
"""My first secure agent."""
@capability("greet")
async def greet(self, name: str) -> dict:
"""Greet someone by name."""
return {
"message": f"Hello, {name}!",
"from": self.config.agent.name
}
if __name__ == "__main__":
agent = HelloAgent.from_config("config.yaml")
agent.run()Create config.yaml:
agent:
name: "hello-agent"
trust_domain: "my-domain.local"
description: "My first secure agent"
capabilities:
- name: "greet"
description: "Greet someone"
input_modes: ["application/json"]
output_modes: ["application/json"]
identity:
provider: "spiffe"
spiffe_endpoint: "unix:///run/spire/sockets/agent.sock"
allowed_trust_domains:
- "my-domain.local"
authorization:
provider: "opa"
opa_endpoint: "http://localhost:8181"
policy_path: "agentweave/authz"
default_action: "deny"
audit:
enabled: true
destination: "stdout"
transport:
tls_min_version: "1.3"
peer_verification: "strict"
server:
host: "0.0.0.0"
port: 8443
protocol: "a2a"
observability:
metrics:
enabled: true
port: 9090
logging:
level: "INFO"
format: "json"Before starting your agent, register it with SPIRE:
# Create a registration entry
docker exec spire-server spire-server entry create \
-spiffeID spiffe://my-domain.local/agent/hello-agent/dev \
-parentID spiffe://my-domain.local/spire/agent/docker \
-selector unix:uid:1000Create policies/authz.rego:
package agentweave.authz
import rego.v1
default allow := false
# Allow all agents in the same trust domain
allow if {
startswith(input.caller_spiffe_id, "spiffe://my-domain.local/")
startswith(input.callee_spiffe_id, "spiffe://my-domain.local/")
}Load the policy into OPA:
curl -X PUT http://localhost:8181/v1/policies/authz \
--data-binary @policies/authz.rego# Set SPIFFE endpoint
export SPIFFE_ENDPOINT_SOCKET=unix:///run/spire/sockets/agent.sock
# Run the agent
python my_agent.pyYou should see:
{
"timestamp": "2025-12-06T10:30:00Z",
"level": "INFO",
"message": "Agent starting",
"agent": "hello-agent",
"spiffe_id": "spiffe://my-domain.local/agent/hello-agent/dev"
}
{
"level": "INFO",
"message": "Server listening",
"host": "0.0.0.0",
"port": 8443
}curl http://localhost:8443/healthcurl http://localhost:8443/.well-known/agent.jsonResponse:
{
"name": "hello-agent",
"description": "My first secure agent",
"url": "https://localhost:8443",
"version": "1.0.0",
"capabilities": [
{
"name": "greet",
"description": "Greet someone",
"input_modes": ["application/json"],
"output_modes": ["application/json"]
}
],
"extensions": {
"spiffe_id": "spiffe://my-domain.local/agent/hello-agent/dev"
}
}Create a second agent to call the first:
from agentweave import SecureAgent
class CallerAgent(SecureAgent):
async def test_call(self):
result = await self.call_agent(
target="spiffe://my-domain.local/agent/hello-agent/dev",
task_type="greet",
payload={"name": "World"}
)
print(result.artifacts[0]["data"])
# Register this agent with SPIRE first!
agent = CallerAgent.from_config("caller-config.yaml")
asyncio.run(agent.test_call())Behind the scenes, the SDK:
- Identity: Fetched X.509 SVID from SPIRE Agent
- Server: Started A2A protocol server with mTLS
- Authorization: Connected to OPA for policy enforcement
- Discovery: Published Agent Card at
/.well-known/agent.json - Observability: Exposed metrics at
:9090/metrics
When the caller agent invokes greet:
- SDK checks OPA policy (allowed because same trust domain)
- Establishes mTLS connection using SPIFFE identities
- Sends A2A task over secure channel
- HelloAgent executes
greetcapability - Result returned over same secure channel
- All calls audited and logged
- Configuration Reference - Detailed config options
- Security Guide - Production hardening
- A2A Protocol - Deep dive on agent communication
- Multi-Agent Example - Orchestrator pattern
Ensure SPIRE Agent is running and socket is accessible:
docker-compose ps spire-agent
ls -l /run/spire/sockets/agent.sockCheck your policy allows the caller:
# Test policy decision
curl -X POST http://localhost:8181/v1/data/agentweave/authz/allow \
-H "Content-Type: application/json" \
-d '{
"input": {
"caller_spiffe_id": "spiffe://my-domain.local/agent/caller/dev",
"callee_spiffe_id": "spiffe://my-domain.local/agent/hello-agent/dev",
"action": "greet"
}
}'Check trust domains match and SPIRE registration is correct:
# List registered entries
docker exec spire-server spire-server entry show
# Verify SVID was issued
docker exec spire-agent spire-agent api fetchDuring development, you can use log-only mode for authorization:
authorization:
provider: "opa"
default_action: "log-only" # Logs denials but allows themWarning: Never use in production!
# Agent watches config file for changes
python my_agent.py --watch-config# Validate config
agentweave validate config.yaml
# Generate SPIRE registration command
agentweave spire-entry config.yaml
# Test agent connectivity
agentweave ping spiffe://my-domain.local/agent/hello-agent/dev- Browse example agents
- Read the architecture overview
- Join the community discussions