SDK Integration

Complete guide to integrating the Spooled SDK into your agent.

Basic setup

import spooled

spooled.init(agent_id="my_agent")

# ... your agent code ...

spooled.shutdown(success=True)

Decorator API (recommended)

import spooled

@spooled.trace(agent_id="my_agent")
def run_agent(query: str):
    result = call_llm(query)
    data = search_tool(result)
    return summarize(data)

# Shutdown is handled automatically by the decorator

Mark individual functions as tools or observation points:

@spooled.tool()
def search(query: str):
    return api.search(query)

@spooled.observe()
def validate(result):
    assert result.is_valid

init() options

ParameterTypeDefaultDescription
agent_idOptional[str]NoneFalls back to SPOOLED_AGENT_ID, then "default"
session_idOptional[str]NoneMulti-agent session correlation ID
parent_run_idOptional[str]NoneParent trace ID for child agents
correlation_contextOptional[Dict]NoneKey-value context for multi-agent sessions
sample_rateOptional[float]NoneOverride SPOOLED_SAMPLE_RATE (0.0–1.0)
tagsOptional[list]NoneTags for fleet grouping
exportersOptional[list]NoneCustom exporters (e.g., OTEL)

Multi-agent orchestration

Use spooled.spawn() to create child recorders that share a session:

import spooled

spooled.init(agent_id="orchestrator")

# Spawn a child agent — linked via session_id + parent_run_id
child = spooled.spawn(agent_id="researcher")
# child is a Recorder instance with its own trace
child.record_interaction(...)
child.stop()

spooled.shutdown(success=True)

Child traces are correlated via session_id and linked via parent_run_id, so behavioral changes in child agents are isolated and tracked independently.

Fleet tagging

spooled.init(
    agent_id="payment_agent",
    tags=["production", "finserv", "v2"]
)

Or via environment variable: SPOOLED_AGENT_TAGS=production,finserv,v2

Sampling

For high-volume agents, sample a fraction of runs:

spooled.init(agent_id="high_volume", sample_rate=0.1)  # Record 10% of runs

Or via SPOOLED_SAMPLE_RATE=0.1. Unsampled runs produce no trace.

OpenTelemetry export

from spooled.exporters import SpooledOTELExporter

spooled.init(
    agent_id="my_agent",
    exporters=[SpooledOTELExporter()]
)

Traces are exported via OTLP to your configured collector (Datadog, Grafana, Honeycomb, etc.).

Fingerprint mode

ModeBehavior
sequence (default)Order-sensitive. Hash includes the exact sequence of interactions.
structuralOrder-insensitive. Hash includes the sorted unique set. Good for ReAct-style loops.
spooled.init(agent_id="react_agent", fingerprint_mode="structural")

Or via SPOOLED_FINGERPRINT_MODE=structural.

Privacy posture

On initialization, Spooled logs its privacy posture:

Spooled privacy posture
  agent_id: my_agent
  local_storage: true
  backend_url: (none)
  capture_mode: structure-only (content is never captured)
  data_sent_to_backend: none (local-only mode)

Call content (prompts, responses, tool argument values) is stripped at the SDK level. See Privacy Architecture for exactly what is and isn't transmitted.

Manual Recorder API

For full control, use the Recorder directly:

from spooled.recorder import Recorder
from spooled.models import InteractionType

recorder = Recorder(
    agent_id="my_agent",
    buffer_size=100,
    flush_interval=5.0,
)
recorder.start()

recorder.record_interaction(
    interaction_type=InteractionType.LLM_CALL,
    input_data={"model": "gpt-4", "prompt": "..."},
    output_data={"response": "..."},
    metadata={"latency_ms": 250, "tokens": 1500},
)

recorder.stop(status=TraceStatus.SUCCESS)
Note
Spooled fails open — if the SDK encounters an error, it silently degrades rather than blocking your agent.