Skip to main content
Use Lemma’s Mastra integration when your app runs agents or workflows through Mastra observability. The integration implements a Mastra ObservabilityExporter that creates one Lemma trace for each Mastra agent_run / workflow_run, maps model generations to Lemma generations, maps tool calls to tools, and preserves nesting (with orphan-safe parent fallback when Mastra hides internal spans). You do not need to wrap Mastra runs in lemma.trace(). Register LemmaMastraExporter once in Mastra’s Observability config, then run agents normally.

Install

Install Mastra and the Lemma SDK:

Register the exporter

Register the Lemma exporter in your Mastra observability config. By default, credentials are read from LEMMA_API_KEY and LEMMA_PROJECT_ID:
You can also pass credentials and options directly, or use the mastra() factory alias:
Then run your agent normally:

What Lemma records

Each Mastra span maps to a Lemma record: Mastra often sets root input to { messages: [...] }. Lemma extracts the latest user message as the trace root input so each turn stays readable; generations still carry the full message list Mastra sent to the model. Every child span — and the root — keeps Mastra’s real startTime / endTime. If a child’s parentSpanId points at a span Mastra never exported, Lemma attaches that child directly under the trace root so parent references never dangle.

Threads / multi-turn

Each Mastra agent.generate() (or workflow run) is one conversation turn and becomes exactly one Lemma trace. Link turns in the same conversation with a shared threadId, and set userId so Lemma can group by person. See Instrumenting multi-turn agents and Building high-quality traces. Lemma resolves threadId and userId from the root span’s metadata or requestContext, checking threadId and userId (then Mastra memory’s resourceId). Pass them via Mastra memory or tracingOptions.metadata:
Override the lookup keys when your app uses different names:
Root input is the current user turn (extracted from Mastra’s { messages } payload when present). Generations carry the full message list sent to that model call (system, prior turns, tool results, and the current user message) as both input and llmInputMessages.

Privacy

The integration records prompts, tool inputs, tool outputs, and model output by default. Disable input/output recording when you need structure and timings without payload contents:

Debugging

Use debug mode to confirm spans are arriving nested under the expected parent:
Look for span recorded logs. Tool and generation spans should include the expected parentId when Mastra exported the parent, or sit directly under the trace when the parent was an internal/hidden span.