Why Behavior Changed
Use this workflow when a team asks:
- why did this route change?
- why did this tool disappear?
- why was this context selected now but not before?
yggdrasil is designed to answer those questions from run traces and structured observability output rather than ad hoc log reading.
Explain One Run
Use explain_run(ctx) to get a structured summary of why a specific run behaved the way it did. It returns a typed RunExplanation — no terminal output, no server.
from yggdrasil.observability import explain_run
ctx = await executor.run(entry_node_id=agent.node_id, query="...")
summary = explain_run(ctx)
The run summary includes:
- hops, routing decisions, context injection, and tool calls
- approval task and pause details for human-in-the-loop workflows
Serialize to JSON for storage or dashboards:
import dataclasses, json
print(json.dumps(dataclasses.asdict(summary), default=str))
Then View It — Terminal Or Browser
Once you have the ctx, choose how to view the full event-by-event trace:
Terminal (Rich tree UI):
from yggdrasil.trace_ui import inspect_trace
inspect_trace(ctx)
# Export as a shareable artifact
inspect_trace(ctx, file="trace.html", format="html")
inspect_trace(ctx, file="trace.txt", format="text")
Browser (interactive, with graph store snapshot):
from yggdrasil.viz import serve_trace
await serve_trace(ctx, store=executor.store)
Browser (live streaming during the run):
from yggdrasil.viz import live_trace
async with live_trace(executor) as viz:
ctx = await executor.run(entry_node_id=agent.node_id, query="...")
Use inspect_trace(ctx) when working in a terminal or exporting a shareable file. Use serve_trace(ctx, store=executor.store) when you want an interactive browser session with the graph store snapshot alongside the trace. live_trace(executor) is for watching a run in progress.
See Observability for the full mode-selector and API reference.
Understand Routing Decisions
The routing stack runs in this order:
decision_table— policy-driven routing (multi-condition rows)route_rules— deterministic guardrails and pauses- LLM or keyword intent inference — interprets agent output
routing_table— maps intent to next node
explain_run(ctx).routing gives you the routing decision for each hop, including the mode (decision_table, route_rules, intent, or default) and which node was chosen.
Practical Investigation Sequence
For a real incident or confusing run:
- run
explain_run(ctx)and checkroutingandtool_calls - use
inspect_trace(ctx)orserve_trace(ctx, store=executor.store)to walk through the full event-by-event trace - compare
ctx.outputsbefore and after the change to isolate the hop where behavior diverged
That sequence usually answers both:
- what the agent did
- why it chose that path
Terminal view — inspect_trace(ctx) from yggdrasil.trace_ui. Use when working in a terminal or exporting a shareable file.
Browser view — serve_trace(ctx, store=executor.store) from yggdrasil.viz. Use when you want an interactive browser session with the graph store snapshot alongside the trace.