Prompt traceability

Every span that used a managed prompt records the exact version by immutable hash — so a trace always shows precisely which prompt ran, even after a deploy label is later moved.

A label like production is a moving pointer. When you look at a trace from last week, "it used production" is not an answer — production may point somewhere else now. Traceability closes that gap: every span records the exact version hash it ran, frozen at run time. Move the label a hundred times afterwards and the trace still tells you the truth.

What gets recorded

When you compile a managed prompt inside a tracked agent run, the SDK stamps the version onto every span emitted in that scope — automatically, with no code change. Each span carries:

AttributeMeaning
trodo.prompt.nameThe prompt's name.
trodo.prompt.version_hashThe immutable version id — the ground truth of what ran. Pinned by hash, so it never changes meaning.
trodo.prompt.labelThe deploy label the fetch followed (production by default). Omitted when you pinned an exact version by hash — the hash is the identity.
trodo.prompt.content_hashsha256 of the content (internal; identical content shares it).

The enclosing run also aggregates the full set of prompts it used, under a trodo.prompts attribute — useful when one agent run compiles several prompts.

The link is made at compile time, because that is the exact moment a specific version becomes the messages sent to the model. get() is often cached or called once at startup; compile() is per-use, so it's the precise "this version ran here" signal.

How it's wired

You don't wire anything — fetch, compile, and run inside your agent as usual. The version rides along:

import trodo from 'trodo-node';

await trodo.wrapAgent('refund-flow', async () => {
  const prompt = await trodo.prompts.get('refund-agent');   // follows `production`
  const { messages, model } = prompt.compile({ order: '1234' });

  // The provider call is auto-instrumented; its span is stamped with
  // trodo.prompt.version_hash automatically.
  await openai.chat.completions.create({ model: model.model, messages });
});
import trodo

with trodo.wrap_agent(agent_name="refund-flow"):
    prompt = trodo.get_prompt("refund-agent")          # follows `production`
    compiled = prompt.compile(order="1234")

    # The provider call is auto-instrumented; its span is stamped with
    # trodo.prompt.version_hash automatically.
    client.chat.completions.create(model=compiled.model["model"], messages=compiled.messages)

Auto-instrumented provider spans (OpenAI, Anthropic, Vercel AI SDK, …), manual withSpan / span blocks, and joinRun / join_run spans are all covered, in both the default trodo transport and OTLP mode.

Seeing it in a trace

Open any trace, select a span, and the span detail panel shows a Prompt field — the name plus a short version hash. The full hash is in the span's raw Attributes (trodo.prompt.*). Copy it and pass it straight back to pin that exact version:

await trodo.prompts.get('refund-agent', { version: 'a3f9c2' });  // the exact version that ran
trodo.get_prompt("refund-agent", version="a3f9c2")   # the exact version that ran

That round-trip — a trace tells you the hash, the hash reproduces the run — is the whole point. A production incident on an agent from three deploys ago resolves to one exact, fetchable version.

Edge cases

  • Compiled outside a run. No active agent run (no wrapAgent / wrap_agent on the stack) → nothing to attach to, so recording is a silent no-op. It never throws.
  • Fallback prompts. If a fetch fell back to your in-code fallback because Trodo was unreachable, there is no real version hash, so the span is not stamped with a prompt version — the isFallback / is_fallback flag is how you detect that run instead. See Caching & availability.
  • Multiple prompts per run. Each span is stamped with the prompt compiled most recently before it was emitted; the run's trodo.prompts holds the complete set.

Where to go next

On this page