ingest() once.
A context token is the payload the host exports. It includes traceId, parentSpanId, threadId, userId, and startedAt. The helpers are startTurn / attachTurn / apply (Python start_turn / attach_turn / apply).
A thread id groups successive conversation turns. It does not join a host and a sandbox into one turn. For later turns in other processes, see Instrumenting multi-turn agents.
Host, child, and coordinator
The work splits across three roles:- Host: process that holds the Lemma client and API key
- Child: sandbox or worker that records the journal
- Coordinator: process that applies the journal and sends (the host, unless another process holds the journal)
ingest(). The child never constructs Lemma and never calls /traces/ingest.
Record the host and child as one turn
Export a token on the host, attach in the child, apply the journal, then end once.1
Start the host root and export a token
Call
startTurn / start_turn, start a sandbox span, and export with that span as parentSpanId. In a sandbox, pass the token as env (for example LEMMA_TURN).2
Attach in the child and record locally
Call
attachTurn / attach_turn with the token. Record generations, tools, and spans on the local handle. Emit local.records() on the app’s existing event channel. Do not set LEMMA_API_KEY in the child.3
Apply the journal and ingest once
On the host,
apply the journal, end the sandbox span, then turn.end() or ingest(). Do not call /traces/ingest from the child. Lemma ingest happens once at the end.export / attachTurn / apply across host and child in production.
- TypeScript
- Python
apply accepts any of:
- Full journal:
local.records() - JSON string: a serialized journal
- One record: a single event
- Array of records: streamed events
apply only updates the in-memory tree on the host or coordinator. It does not call /traces/ingest. Stream journal events into apply as they arrive, or apply the full journal once. Send to Lemma once with turn.end() or ingest() after the sandbox finishes.
Assemble a trace from a stored journal
When you have a token and journal and no live turn handle, build aTraceContext and ingest() once. The journal can be a file or a queued payload:
- TypeScript
- Python
Recover when the sandbox exits uncleanly
If the sandbox dies before a complete journal, apply whatever records arrived. End the sandbox span asERROR, leave incomplete tools as they are, then fail and end() so one payload still goes out.
- TypeScript
- Python
turn.end() is strict: a 4xx/5xx from Lemma throws so you can retry the same payload. Automatic lemma.trace() delivery fails open.
Helpers for each role
Journal fields are camelCase in both languages (
traceId, parentSpanId, parentId, startedAt, …). A TypeScript host can apply a Python child’s journal. A Python host can apply a TypeScript child’s journal.
Related pages
Agent traces
Callback traces, handles, and
ingest() in one process.Instrumenting multi-turn agents
New root per user turn, same
threadId for the conversation.Threads & context
threadId and userId on the root.Common issues
Two roots, missing children, sparse ingest.