Integrations
Etch is framework-agnostic. If your agent calls Anthropic or OpenAI, uses
LangChain / LangGraph / CrewAI / AutoGen / LlamaIndex, speaks MCP, or
emits OpenTelemetry gen_ai.* traces, you can audit
it with one of the four ingestion layers below. All four converge on the
same authenticated audit chain, and all four surface in the same
Sessions view.
Install
pip install etch-client
The etch-client package bundles all four integration
layers. Import only what you use. Currently in beta, ping the
operator for a pre-release wheel.
Layer 1. LLM-provider wrappers
Drop-in replacements for the Anthropic and OpenAI Python SDKs. Every
messages.create or chat.completions.create
records to Etch. Works with LangGraph, CrewAI, AutoGen, and every other
framework that uses these SDKs under the hood, because the wrapping
happens at the SDK layer.
Anthropic
from etch.integrations.anthropic_client import EtchAnthropic
client = EtchAnthropic(
api_key="sk-ant-...",
etch_app_token="ep_live_...",
etch_project_id="my-project",
)
response = client.messages.create(
model="claude-opus-4-7",
max_tokens=1024,
messages=[{"role": "user", "content": "hi"}],
)
OpenAI + any OpenAI-compatible provider
Any provider that speaks the OpenAI chat-completions API works via
EtchOpenAI. Pass provider_label so the
dashboard attributes each call to the right upstream instead of showing
everything as openai:....
from etch.integrations.openai_client import EtchOpenAI
# OpenAI
client = EtchOpenAI(
api_key="sk-...",
etch_app_token="ep_live_...", etch_project_id="my-project",
)
# Groq
client = EtchOpenAI(
api_key="gsk_...",
openai_kwargs={"base_url": "https://api.groq.com/openai/v1"},
provider_label="groq",
etch_app_token="ep_live_...", etch_project_id="my-project",
)
# OpenRouter
client = EtchOpenAI(
api_key="sk-or-...",
openai_kwargs={"base_url": "https://openrouter.ai/api/v1"},
provider_label="openrouter",
etch_app_token="ep_live_...", etch_project_id="my-project",
)
# HuggingFace Inference Providers (router)
client = EtchOpenAI(
api_key="hf_...",
openai_kwargs={"base_url": "https://router.huggingface.co/v1"},
provider_label="hf", # or "hf-together" / "hf-fireworks" / etc.
etch_app_token="ep_live_...", etch_project_id="my-project",
)
# Perplexity, Fireworks, Cerebras, together.ai, DeepSeek direct, etc.
# same shape: set base_url + provider_label.
What gets recorded per call: model, input message count,
input_hash, output_hash, input/output tokens, stop_reason, tool_calls_seen.
Full prompt content is NOT sent to Etch by default, only hashes.
Opt in with persist_full_content=True.
What the dashboard shows: per-provider filtering via the Models
column on the Sessions list. A call routed through Groq shows as
groq:llama-3.3-70b; through OpenRouter as
openrouter:anthropic/claude-4.7; through the HF router as
hf-together:meta-llama/Llama-3.3-70B, etc.
Layer 2. OpenTelemetry receiver
Every gen_ai.* span becomes an event. Covers LangChain,
LangGraph, LlamaIndex, Semantic Kernel, PydanticAI, Griptape, Bedrock
anything emitting the OTel GenAI semantic conventions. Two
integration shapes:
Hosted (recommended), point your collector at etch.systems
# In your OTel collector config (OTLP/HTTP exporter):
exporters:
otlphttp/etch:
endpoint: https://etch.systems/projects/my-project/otel/v1/traces
headers:
authorization: Bearer ep_live_...
encoding: json
Or point your app's OTel SDK directly at the same URL. No sidecar required. Etch parses the OTLP/HTTP JSON payload and records every span.
Self-hosted, run the receiver in your infra
from starlette.applications import Starlette
from etch.integrations.otel_receiver import mount_otel_starlette
app = Starlette()
mount_otel_starlette(
app,
etch_app_token="ep_live_...",
etch_project_id="my-project",
)
# Point your collector at http://your-host/otel/v1/traces
Status: OTLP/HTTP JSON path shipping today. Full OTLP-protobuf ingest is on the roadmap.
Layer 3. MCP proxy
Sit between an agent and any upstream MCP server(s). Every
tools/call is recorded, then forwarded transparently. Works
with Claude Code, Cline, Cursor, and any MCP-native client.
Hosted, point your agent's MCP config at etch.systems
# In your agent's MCP client config:
{
"mcpServers": {
"filesystem-audited": {
"url": "https://etch.systems/projects/my-project/mcp-proxy",
"headers": {
"Authorization": "Bearer ep_live_...",
"X-Etch-MCP-Upstream": "https://your-filesystem-mcp.internal",
"X-Etch-MCP-Upstream-Name": "filesystem",
"X-Etch-MCP-Upstream-Authorization": "Bearer <upstream-token>"
}
}
}
}
Every tools/call is transparently forwarded to the URL in
the upstream header. Etch records the call name, argument hashes, and
result status, then returns the upstream's response byte-for-byte.
Self-hosted, in-process middleware
from etch.integrations.mcp_proxy import EtchMCPProxy
proxy = EtchMCPProxy(
upstream_base_url="http://your-filesystem-mcp:8000",
upstream_name="filesystem",
etch_app_token="ep_live_...",
etch_project_id="my-project",
)
# Point your agent at proxy.forward_tools_call(...) OR
# use mount_proxy_starlette() to expose an HTTP endpoint.
Layer 4, framework SDK shims
Thin adapters for the biggest agent frameworks. Use these when you want finer-grained per-node / per-tool observability than the LLM proxy provides.
LangChain
from etch.integrations.langchain_callback import EtchLangChainCallback
cb = EtchLangChainCallback(
etch_app_token="ep_live_...",
etch_project_id="my-project",
)
chain.invoke({"question": "..."}, config={"callbacks": [cb]})
LangGraph
from etch.integrations.base import EtchRecorder, RecorderConfig
from etch.integrations.langgraph_shim import etch_trace
recorder = EtchRecorder(RecorderConfig(
app_token="ep_live_...",
project_id="my-project",
))
@etch_trace(recorder, node_name="planner",
session_id_fn=lambda state: state.get("run_id"))
def planner_node(state):
return {"plan": "..."}
CrewAI
CrewAI routes LLM calls through LiteLLM to the underlying provider SDK. Wrap the provider client once and every agent's calls flow through Etch.
from etch.integrations.openai_client import EtchOpenAI
from crewai import Agent, Task, Crew, LLM
# Wrap the provider SDK. CrewAI-compatible LLM object.
etch_client = EtchOpenAI(
api_key="sk-...",
etch_app_token="ep_live_...",
etch_project_id="my-project",
provider_label="openai",
)
llm = LLM(model="gpt-4o", client=etch_client)
researcher = Agent(role="Researcher", goal="...", llm=llm)
crew = Crew(agents=[researcher], tasks=[Task(description="...", agent=researcher)])
crew.kickoff()
AutoGen
AutoGen accepts a raw OpenAIWrapper-compatible client via
llm_config. The Etch wrapper is a drop-in replacement.
from etch.integrations.openai_client import EtchOpenAI
from autogen import AssistantAgent, UserProxyAgent
etch_client = EtchOpenAI(
api_key="sk-...",
etch_app_token="ep_live_...",
etch_project_id="my-project",
provider_label="openai",
)
assistant = AssistantAgent(
name="assistant",
llm_config={"model": "gpt-4o", "client": etch_client},
)
user = UserProxyAgent(name="user", human_input_mode="NEVER")
user.initiate_chat(assistant, message="...")
LlamaIndex
LlamaIndex uses provider-specific LLM classes. Pass the Etch-wrapped provider client into the constructor for full audit coverage.
from etch.integrations.anthropic_client import EtchAnthropic
from llama_index.llms.anthropic import Anthropic
from llama_index.core import VectorStoreIndex, Document
etch_client = EtchAnthropic(
api_key="sk-ant-...",
etch_app_token="ep_live_...",
etch_project_id="my-project",
)
# LlamaIndex's Anthropic LLM accepts the raw client.
llm = Anthropic(model="claude-opus-4-7", client=etch_client)
index = VectorStoreIndex.from_documents([Document(text="...")])
query_engine = index.as_query_engine(llm=llm)
query_engine.query("...")
Alternative: LlamaIndex also emits OpenTelemetry gen_ai.*
spans via its OpenInference tracer — see Layer 2 above.
Semantic Kernel, PydanticAI, Griptape, Bedrock Agents, Vertex AI
All emit OpenTelemetry gen_ai.* semantic-convention spans natively.
Point their OTel exporter at Etch (Layer 2 above) and every request lands
in the same audit chain. No per-framework wrapper needed.
Prefer a one-command install for AI coding agents?
If your workflow is agent-first (Claude Code, Cursor, Cline, Codex, etc.) rather than framework-first, skip the layers above and use the per-adapter install pages at etch.systems/docs/install. Each of the 12 supported coding agents has a stable install page with a copy-paste command.
Which layer for which framework?
| Framework | Recommended layer | Why |
|---|---|---|
| Custom Anthropic / OpenAI SDK | Layer 1 | Direct wrapping, zero framework dependency. |
| LangChain | Layer 4 callback | Per-node visibility. Layer 1 also works. |
| LangGraph | Layer 4 @etch_trace | Per-node inputs/outputs. |
| CrewAI | Layer 1 | CrewAI uses LiteLLM → provider SDK. |
| AutoGen | Layer 1 | Same reason. |
| LlamaIndex | Layer 2 OTel | Ships gen_ai.* spans natively. |
| Semantic Kernel, PydanticAI, Griptape | Layer 2 OTel | All emit OTel gen_ai.* semantic conventions. |
| Claude Code, Cline, Cursor | Layer 3 MCP proxy | MCP-native. Layer 1 also works for the LLM step. |
| Bedrock Agents | Layer 2 OTel | Bedrock emits gen_ai.* traces to CloudWatch/OTel. |
| Groq | Layer 1 (provider_label="groq") | OpenAI-compat API. |
| OpenRouter | Layer 1 (provider_label="openrouter") | OpenAI-compat API. |
| HuggingFace Inference Providers | Layer 1 (provider_label="hf") | OpenAI-compat router; also per-provider (hf-together, hf-fireworks, etc.). |
| Perplexity / Fireworks / Cerebras / together.ai / DeepSeek | Layer 1 (provider_label="<label>") | All expose OpenAI-compat endpoints. |
The privacy default
Every layer defaults to hash-only recording: Etch never sees your prompts, tool arguments, or response content, only cryptographic fingerprints. That means your PII stays in your infrastructure, and the audit trail proves what you did without exposing what was in the data.
Opt in to full-content persistence per layer via
persist_full_content=True. Use case:
regulator-facing audit archives where the content itself must be
inspectable later.
What you see afterwards
Every event lands in the Sessions tab
of your project's dashboard, grouped by session_id. One
click on a session shows the chronological reconstruction, every
LLM call, every tool call, every OTel span, in the order it
actually happened.
Support
Email support@etch.systems. First-integration check-ins are on the house.