rendfly
See your agent's full execution tree. One line.
rendfly is observability for LLM apps and AI agents. Add this SDK (or point your traffic at rendfly's proxy) and you get a live trace of every LLM call, tool call, and retrieval step your agent makes — with cost and latency at each step — so when something breaks in production you can see exactly where, and why.
Built on OpenTelemetry and OpenInference, so it plugs into infrastructure you likely already trust.
Install
pip install rendfly
OpenAI and Anthropic are auto-instrumented out of the box — nothing extra to install. For CrewAI, LangChain/LangGraph and LlamaIndex support:
pip install "rendfly[all]"
(Or install just what you need: pip install "rendfly[crewai]" / "rendfly[langgraph]" / "rendfly[llama-index]".)
Quickstart
import rendfly
rendfly.init() # reads RENDFLY_API_KEY; endpoint default https://proxy.rendfly.com
from openai import OpenAI # auto-instrumented, nothing else to write
OpenAI().chat.completions.create(...) # -> llm span: tokens, model, cost-ready, redacted body
@rendfly.agent # span kind=agent
def support(q: str) -> str:
plan = make_plan(q) # span kind=task
with rendfly.span("vector-search", kind="retrieval") as s:
s.set_attribute("top_k", 8) # a step your LLM provider can't see
return db.search(q)
@rendfly.task
def make_plan(q): ...
with rendfly.session("conv-123"): # ties everything below to one conversation
support("...")
Set RENDFLY_API_KEY (an rfk_proj_... project key from your rendfly project) in your environment and you're capturing traces. No key set — the SDK quietly runs as a no-op and your app behaves exactly as before; a missing or invalid key never crashes startup.
Merge with your proxy traffic
If you already route your LLM calls through rendfly's proxy (swap base_url to https://proxy.rendfly.com, one line, no other code changes), the proxy is already capturing every LLM call it forwards. Wrapping a block of code in rendfly.session("conv-123") — using the same conversation id you already track — tells the SDK to stamp that same id on every span it creates inside the block.
The result is one merged execution tree per conversation, one trace: the LLM calls the proxy already saw, plus the tool calls, retrieval steps, and agent/task structure that only your code knows about. You don't have to choose one integration over the other or migrate anything — the SDK is purely additive on top of the proxy. Skip rendfly.session(...) and the SDK still works fine; you just get a standalone trace instead of a merged one.
What gets instrumented
rendfly.init() instruments the libraries it supports that you actually have installed: openai, anthropic, crewai, langchain, llama_index. Nothing is instrumented for a library that isn't there, and rendfly.diagnostics()["instrumented"] lists only what really attached.
One detail is worth knowing. LangChain and LlamaIndex record their own LLM span for a call the provider instrumentor also sees, so a single call shows up as two spans in the waterfall: the chain-level view and the HTTP-level view underneath it. Both are kept on purpose — dropping either would cost you real information — and rendfly counts the tokens and the cost once, on the outer span. Your totals are the totals, whichever frameworks you have installed.
If you would rather see one span per call, name the layer you want:
rendfly.init(instrument=["langchain"]) # chain-level spans only
rendfly.init(instrument=["openai"]) # provider-level spans only
rendfly.init(instrument=False) # decorators and rendfly.span() only
Instrumentation rendfly doesn't ship
rendfly.tracer_provider() returns rendfly's OpenTelemetry provider. Pass it to any other instrumentor and its spans join the same traces:
SomeOtherInstrumentor().instrument(tracer_provider=rendfly.tracer_provider())
init() also registers that provider as the process-wide OpenTelemetry provider when your application hasn't set one, so trace.get_tracer(...) spans of your own land in rendfly too. If you already run your own OpenTelemetry setup, rendfly leaves it alone and you wire it explicitly with the call above.
Security & data handling
By default, rendfly captures message bodies and tool arguments but scrubs every value client-side, before anything leaves your process — PII and secrets never cross the wire in the first place. Control how much is captured with capture_content in rendfly.init():
capture_content |
Message bodies / tool args | Client-side scrub | Use |
|---|---|---|---|
redacted (default) |
captured, scrubbed | yes | balanced — see what the agent did, PII is stripped before export |
metadata |
not sent | n/a | regulated environments — only kind, model, tokens, latency, status, and tool names leave your process |
raw |
captured verbatim | no (server still redacts) | maximum fidelity, explicit opt-in |
redacted is the secure default: unless you deliberately set capture_content="raw", nothing goes out unscrubbed.
This table describes what the auto-instrumentation captures. Spans you create yourself — @rendfly.agent / @rendfly.task / @rendfly.tool and rendfly.span(...) — record name, kind, timing and status only; your function arguments are never read, so there is nothing to scrub. Attach what you want on the span explicitly with set_attribute, and it goes through the same scrubbing.
A few more things worth knowing:
- Your API key is sent only as an
Authorizationheader on export — it is never written into a span, a log line, or an exception message, and is masked to its last 4 characters in any diagnostic output. - Traffic requires
https://by default;http://is accepted only forlocalhost, and only if you explicitly passallow_insecure=True. redact_patterns,redact_keys, andredactorlet you extend or fully replace the built-in scrubbing rules (emails, card numbers, tokens, and more) with your own.drop_spansandsamplerlet you exclude a whole subsystem or sample volume, so sensitive code paths never get captured at all.- Every entry point (decorators,
span(), instrumentation, export) fails safe: an internal SDK error is logged and swallowed, never raised into your application or your LLM call path.
Configuration reference
Every argument is optional and falls back to an environment variable where noted; secure defaults apply if you pass nothing.
rendfly.init(
api_key=None, # env RENDFLY_API_KEY
endpoint=None, # env RENDFLY_ENDPOINT; default https://proxy.rendfly.com
project=None, # optional label; your api_key already scopes the project
instrument=True, # True = auto-detect; or a list, e.g. ["langchain", "openai"]
session_id=None, # optional default session id applied to every span
capture_content="redacted", # "redacted" (default) | "metadata" | "raw"
redact_patterns=None, # extra regex patterns for value scrubbing
redact_keys=None, # extra attribute-key patterns to always drop
redactor=None, # callable(str) -> str to fully override value scrubbing
drop_spans=None, # callable(span) -> bool to exclude specific spans
sampler=None, # OpenTelemetry sampler; default parent-based always-on
max_attr_bytes=16384, # per-value truncation cap, in bytes
resource_attributes=None, # extra resource attributes (never put secrets here)
allow_insecure=False, # permit http:// for localhost only — dev use only
ca_bundle=None, # path to a private CA bundle, for on-prem collectors
client_cert=None, # path to a client certificate, for mTLS
console_debug=False, # print post-redaction spans to console, key masked
)
License
MIT — see LICENSE.
Metadata
Release files for rendfly 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| rendfly-0.1.2.tar.gz | 16.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| rendfly-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 37.9 kB
Release files / rendfly-0.1.2.tar.gz
| Download URL | rendfly-0.1.2.tar.gz |
|---|---|
| Size | 16.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
41bd6336e6cb7ee8a402c8ce09d70b3dc36aeb31bb1c1911c0ecb1710e665cf0
|
|
BLAKE2b-256 checksum How to use checksums |
017c6679c950b27369c0bcdb2dfda823f2db5b3da5cbb3f7dc4a6f83f71566c3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 9, 2026.
Transparency logRelease files / rendfly-0.1.2-py3-none-any.whl
| Download URL | rendfly-0.1.2-py3-none-any.whl |
|---|---|
| Size | 20.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bef94df754ad21bb3592900839f20ab24d92a6f43f4269793092d6eb18b88f66
|
|
BLAKE2b-256 checksum How to use checksums |
470acb52d9665e4204af9be545b142d9d73d9b716d69e976038358a0278133b1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 9, 2026.
Transparency log