Web app
Traces
A trace is one request taken apart: every check that ran on it, what each returned, where the values in its tool calls came from, and why it was blocked.
In the web app Traces
When to use this
- Someone asks why a response was blocked. Start from the trace, not the finding.
- A detector got it wrong, and you want to say so where it counts.
- To turn a real request into an eval case (copy its id to a suite).
The list
/app/traces loads GET /api/traces?limit=150 with the filters in the URL: all, blocked (verdict=block), escalated (verdict=escalate), injection, PII and secrets (entity_type=), and an agent drop-down. Columns: trace id, agent, verdict, environment, model, intent, when. The caret expands a row to its decisions and detector runs without leaving the list.
trace agent verdict env model intent
trc_01m4699s1xf8phecv5 Support Triage Agent block production echo-1 summarise the Q3 refunds document
trc_01m4699rvmjmf36y1c marketing-copy-bot allow production echo-1 —
trc_01m4699rsf3he2g5ss Support Triage Agent allow production echo-1 summarise the Q3 refunds document
trc_01m4699rrb1591azhg Support Triage Agent allow production echo-1 answer a customer refund questionThe trace page
In the web app Traces → a trace
/app/traces/<id> loads GET /api/traces/{id}. The heading is the intent the caller sent, or the surfaces that were checked ("Checked input and output"), followed by the overall verdict. Then the agent, environment, time and trace id. In order down the page:
| Panel | What it shows |
|---|---|
| Why — <surface> | One per decision that did not simply allow. The summary sentence; the rule's reason; Decided by: the detector, the entity, its offset and score, and the OWASP id; Also matched: other matches that did not decide it; What to do; and a Disagree? box to file a false positive. In observe mode it opens by saying nothing was stopped and this is what would have happened. |
| Span timeline | Each span with its kind, name and duration. |
| Argument provenance | Each tracked value (a JSON path), where it came from (user, retrieved, tool result…) and whether that source is trusted. This is what the taint rules read before an irreversible tool runs. |
| Decisions | Per surface: tool, verdict, mode, rules fired (id, effect, reason, controls) and latency. |
| Detector runs | Per detector and surface: status, score, time, the entities it found with a masked sample, and a was this right? control. |
block on tool_result: INJECTION.INSTRUCTION_OVERRIDE matched at offset 59–91 with score 1.00,
which rule `injection.indirect` treats as block
Instruction-like content found in untrusted retrieved or tool content (indirect prompt injection).
Decided by injection.heuristic found INJECTION.INSTRUCTION_OVERRIDE at offset 59–91 scoring 1.00 · LLM01
Also matched INJECTION.COVERT_INSTRUCTION (1.00), INJECTION.ROLE_DELIMITER (0.70)
Not what decided this one.
What to do
The instruction arrived in untrusted content. Fix the source, or lower the capability ceiling
for arguments derived from it rather than relaxing the detector.A trace with no spans, decisions or detector runs is shown as nothing checked, not as allowed. That happens when a turn made no governed call, for example a tool-call integration on a turn where the model called no tool. An empty trace is not a pass.
Was this right? Feedback and what it feeds
On each detector run tied to a decision, pick correct — true positive, wrong — false positive or missed something and press file feedback. The File as a false positive button in a Why panel does the same with a note. Both send POST /api/guardrails/feedback with the decision, detector and entity, and return you to the trace with "feedback recorded".
- One label per decision per person: labelling the same decision again replaces your earlier label.
- Feedback changes nothing on its own. It appears in the Feedback log on Guardrail tuning, where an open false positive is one click (suppress 30d) from a suppression scoped to that agent and entity.
- It feeds precision per detector and threshold recommendations. A detector needs at least five labelled verdicts before any recommendation is made.
- agentfox policy proposals from-labels turns clean "raise the threshold" recommendations into change proposals for the rules involved, and applies nothing. With too few labels it files nothing:
agentfox policy proposals from-labels --days 30filed 0, refreshed 0, superseded 0Correlation with Langfuse and LangSmith
If your agent already sends traces to Langfuse, LangSmith or an OpenTelemetry backend, AgentFox stores the join key (a W3C traceparent or the vendor's trace header) when it records the decision. The web app does not show these links yet. Use the API:
GET /api/traces/{id}returns alinkslist: system, external trace and run ids, project and URL.GET /api/traces/resolve?system=langfuse&external_id=…goes the other way: from their trace or run id to the governed trace.systemislangsmith,langfuseorotel.
curl -s "http://127.0.0.1:8080/api/traces/resolve?system=langfuse&external_id=abc123" \
-H "Authorization: Bearer $AGENTFOX_API_TOKEN"{"detail":"no governed trace correlates with that id"}Setting this up is in Traces and integrations.
Common tasks
| You want to | Run |
|---|---|
| Open a trace by id | ⌘K, paste trc_… |
| Every blocked request for one agent | /app/traces?verdict=block&agent=support-triage |
| Draft rule changes from your false-positive labels | agentfox policy proposals from-labels --days 30 |
| Make a trace a regression case | Evaluation → a suite → Promote a trace |
What can go wrong
- "not tied to a decision" in the feedback column. That detector run fed no decision, so there is nothing to label.
- The trace shows "nothing checked". No governed step ran. Guard the prompt surface too, not only tool calls; see One line in Python.
- Masked samples are unreadable. By design: samples are masked at capture and the original value is not stored anywhere to unmask.
Limits
- No CLI command lists or shows traces; use the page or
GET /api/traces. - The list shows the most recent 150 matching traces; there is no paging.
- External trace links are stored but not shown in the web app.