Documentation Index
Fetch the complete documentation index at: https://docs.trodo.ai/docs/llms.txt
Use this file to discover all available pages before exploring further.
What / When / Minimum
When your agent makes an HTTP call to another of your services (microservice, worker API, internal tool), you want the downstream work to appear as nested spans in the same run — not as a separate run with no link back. Trodo solves this with two headers —X-Trodo-Run-Id and X-Trodo-Parent-Span-Id — and a symmetric pair of helpers:
- Caller:
propagationHeaders()→ inject into the outbound request. - Callee:
expressMiddleware()/fastapi_middleware()→ detect headers, calljoinRunautomatically.
The recipe
(a) Caller — inject headers
- Node.js
- Python
(b) Callee — Express middleware
X-Trodo-Run-Id; if present, it opens a span (kind='agent', named http.POST./search by default) under the caller’s run and runs the handler inside that context. Any withSpan inside the handler nests below it.
If no header is present, the middleware is a pure pass-through — the handler runs with no active run, so tracking is a silent no-op.
(c) Callee — FastAPI middleware
(d) Callee — manual joinRun (workers, queues, gRPC)
When you can’t use HTTP middleware — a BullMQ worker, an SQS consumer, a gRPC handler — call joinRun yourself:
Full example — two services, one run
service-a/parent.js (receives user traffic, orchestrates)parent-service with:
http.POST./searchspan (auto-opened by the middleware on service-b)kb.search(retrieval) ← nested inside because it was inside the middleware’s context
Verification
After triggering a request,trodo.currentRunId() inside the handler on service-b returns the same UUID the parent generated. That’s the single strongest signal propagation worked. The scenarios in backend/scripts/agent-scenarios/12-crossservice-node-node/ demonstrate this end-to-end.
Headers reference
| Header | Type | Set by | Read by |
|---|---|---|---|
X-Trodo-Run-Id | UUID | propagationHeaders() | middleware / manual joinRun |
X-Trodo-Parent-Span-Id | UUID | propagationHeaders() | middleware / manual joinRun |
X-Trodo-Agent-Name | string | (optional) caller | middleware uses for default span name |
Gotchas
- The callee’s SDK must be initialised (
trodo.init) with any valid site id — it doesn’t need to be the same as the caller’s, because the run is identified by UUID. In practice, use the same site so both services’ metrics land in the same team. - Circular calls (A→B→A) work but produce a deep waterfall. Trodo deduplicates spans by UUID, so no double-counting.
- If the callee’s handler throws before awaiting the middleware’s wrapped work, the joined span is recorded as
error— parent’serror_countincrements. - Browser-originated requests never carry Trodo headers (browsers don’t have
propagationHeaders). Propagation is server-to-server only.
See also
- Sub-agents — when you want a separate run linked via
parent_run_idinstead of a joined span. - Propagation internals — how ALS / contextvars hand off context through async boundaries.