Working with Agents
The Curate-Me SDK manages agents through the client.agents sub-client. Agents are
server-side resources identified by an opaque agent_id. You create, list, update,
and run them through the SDK — the platform handles execution, governance, and cost
recording for you. There is no local base class to subclass.
from curate_me import CurateMe
# Initialize the client (or use CurateMe.from_env())
client = CurateMe(api_key="cm_sk_xxx", org_id="org_xxx")Listing and Fetching Agents
# List agents (async)
agents = await client.agents.list(limit=50)
for agent in agents:
print(agent.id, agent.name, agent.model, agent.status)
# Fetch a single agent by ID
agent = await client.agents.get("agt_123")Every method has a synchronous variant suffixed with _sync:
agents = client.agents.list_sync(limit=50)
agent = client.agents.get_sync("agt_123")Creating an Agent
Provide a name and a model identifier. description, config, and metadata
are optional.
agent = await client.agents.create(
name="content-analysis",
model="claude-sonnet-4-6",
description="Analyzes content and extracts structured metadata.",
config={
"temperature": 0.1,
"max_tokens": 1024,
},
)
print(agent.id) # e.g. "agt_123"Running an Agent
Call client.agents.run() with the agent_id and an input dict. The call returns an
AgentRun describing the completed (or failed) execution.
run = await client.agents.run(
"agt_123",
input={"content": "The product launch was a success. Sales exceeded expectations."},
)
print(run.status) # ExecutionStatus, e.g. "completed"
print(run.output) # the agent's result dict
print(run.cost) # cost in USD for this run
print(run.tokens_used) # total tokens consumedrun() accepts optional config, metadata, and timeout (seconds) arguments to
override runtime behaviour for a single invocation.
The AgentRun Result
AgentRun carries the outcome of an execution:
| Field | Purpose |
|---|---|
id | Unique run ID |
agent_id | The agent that was run |
status | ExecutionStatus — pending, running, completed, failed, cancelled, or timeout |
input | The input data passed to the run |
output | The agent’s result dict (when completed) |
error | Error message (when failed) |
duration_ms | Wall-clock duration of the run |
cost | Cost of the run in USD |
tokens_used | Total tokens consumed |
trace_id | W3C trace ID for distributed tracing |
Streaming Execution
For real-time progress, use client.agents.stream(). It yields StreamEvent objects
as the run proceeds.
async for event in client.agents.stream(
"agt_123",
input={"content": "Long document to analyze..."},
):
print(event.type, event.data)Each StreamEvent has a type drawn from the EventType enum and a data payload:
| Event Type | Purpose |
|---|---|
agent_start | The agent has begun execution |
token | Streams individual tokens during generation |
agent_progress | Reports intermediate progress |
agent_complete | Successful completion with a result |
agent_error | An error occurred during execution |
tool_call / tool_result | Tool invocation and its result |
guardrail_check / guardrail_violation | Governance guardrail events |
Managing Runs
# List historical runs for an agent
runs = await client.agents.list_runs("agt_123", limit=20)
# Fetch a single run
run = await client.agents.get_run("agt_123", "run_456")
# Cancel an in-progress run
run = await client.agents.cancel_run("agt_123", "run_456")Updating and Deleting
# Update fields on an agent
agent = await client.agents.update(
"agt_123",
description="Updated description",
model="claude-opus-4-7",
)
# Delete an agent
await client.agents.delete("agt_123")The @agent Decorator
If you want to track a local Python function as a Curate-Me agent — adding tracing and
agent-run records — use the @agent decorator. The decorated function takes an input
dict and returns a result dict.
from curate_me import agent
@agent(name="summarizer", model="claude-sonnet-4-6", tags=["analysis"])
async def summarize_text(input: dict) -> dict:
text = input["text"]
# ... your summarization logic ...
return {"summary": "..."}
result = await summarize_text({"text": "Some long passage of text."})For lighter-weight tracing of any function (not just agents), use the @trace
decorator:
from curate_me import trace
@trace(name="my_operation")
async def my_function(query: str) -> str:
return await process(query)Governance Is Applied Server-Side
Note: Cost caps, PII scanning, rate limits, model allowlists, and HITL approvals are enforced by the Curate-Me gateway, not by the SDK. When you run an agent, the platform applies the governance chain and records cost automatically. You do not wire these checks into your own code. See the governance chain docs for the policy pipeline.
Testing
The SDK’s agent surface is exercised by the package test suite:
cd packages/sdk-python
poetry run pytest tests/ -vTo run the gateway/agent tests on the backend:
cd services/backend
poetry run pytest tests/services/autopilot/ -vDefining Reusable Templates (Autopilot)
To ship a reusable, governed agent template that runs on the platform’s Autopilot
engine (rather than a one-off run), author a template under
services/backend/src/services/autopilot/templates/ with a SKILL.md contract. See
the Autopilot template contract
and existing templates such as dev_team, cfo, and security_audit for reference.