Skip to content
Development
Skill

/explanation-traces

Query and display structured decision traces from routing, agent selection, and skill execution.

From plugin
vexjoy-agent
421122 skills198 agents11 commands76 hooks
Install
$ npx -y skills add notque/vexjoy-agent --skill explanation-traces --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/explanation-traces

Context preview

The summary Claude sees to decide when to auto-load this skill.

Query and display structured decision traces from routing, agent selection, and skill execution.

SKILL.md

explanation-traces.SKILL.md
name: explanation-traces
description: "Query and display structured decision traces from routing, agent selection, and skill execution."
user-invocable: true
argument-hint: "<optional: specific decision to explain>"
allowed-tools:
  - Read
  - Bash
  - Glob
  - Grep
routing:
  triggers:
    - "why did you"
    - "explain routing"
    - "show trace"
    - "decision log"
    - "why that agent"
    - "explain decision"
    - "show decisions"
    - "trace log"
  force_route: true
  not_for: "general 'why did the test fail' debugging, explaining concepts to a user, code documentation, stack traces — only for querying recorded routing/agent decisions"
  pairs_with: []
  complexity: Simple
  category: analysis

Explanation Traces: Structured Decision Query

Overview

This skill reads the per-dispatch route event log and presents routing decisions and their outcomes as a human-readable timeline. It answers "why did I get routed here?" from what was recorded at decision time — never from post-hoc reconstruction or rationalization.

**The log**: `<CLAUDE_LEARNING_DIR>/route-events.jsonl`, default `~/.claude/learning/route-events.jsonl`. Append-only JSONL — one JSON object per line. Written via `hooks/lib/route_events.py` by two producers:

| Producer | Fires on | Appends | |---|---|---| | `hooks/routing-decision-recorder.py` | PostToolUse (Agent dispatch) | One DECISION event per /do-routed dispatch | | `hooks/routing-outcome-finalizer.py` | UserPromptSubmit | One OUTCOME event when it finalizes a pending dispatch |

The log is auxiliary instrumentation: writes are failure-safe (worst case one lost line), and the aggregate routing rows in learning.db stay authoritative for the confidence loop.

**Key constraints baked into the workflow:**

  • Read-only: this skill never modifies the log or any other file
  • Answers must come from recorded events, not from memory or inference about what "probably happened"
  • If no log exists, name the real path and the real producing hook rather than guessing at decisions
  • When the user asks about a specific decision, filter to that decision — skip the full dump
  • `ts` (epoch seconds) and recorded fields are authoritative; keep their precision
  • `request_snippet` is private session data: show it to this session's own user, and keep it out of anything that leaves the session (PR bodies, issues, exports) — report counts there instead

---

Instructions

Phase 1: LOCATE

**Goal**: Find the route event log.

**Step 1: Resolve the path and check it**

LOG="${CLAUDE_LEARNING_DIR:-$HOME/.claude/learning}/route-events.jsonl"
wc -l "$LOG"

`CLAUDE_LEARNING_DIR` redirects the log (tests and redirected DBs use it); unset means the default `~/.claude/learning/`.

**Step 2: Handle missing log**

If the file is absent or empty, stop and inform the user:

No route event log found at ~/.claude/learning/route-events.jsonl
(or $CLAUDE_LEARNING_DIR/route-events.jsonl when that variable is set).

The log is created on the first /do-routed dispatch by the
routing-decision-recorder hook (hooks/routing-decision-recorder.py).
An empty or missing log means no /do-routed dispatch has been recorded
yet — or merged hook changes were never synced to ~/.claude; run
hooks/sync-to-user-claude.py or restart the session.

Recorded events are the only source this skill reads. Reconstructing decisions from memory or conversation history defeats its purpose — with no log, there is nothing to read, and the honest answer is exactly that.

**GATE**: Log found and non-empty. Proceed only when gate passes.

Phase 2: PARSE

**Goal**: Extract events and filter to the user's query.

**Step 1: Read the events**

Parse each line as one JSON object. Two event types (full semantics: `references/trace-schema.md`; source of truth: `hooks/lib/route_events.py`).

DECISION — one per /do-routed dispatch:

| Field | Meaning | |---|---| | `ts` | Epoch seconds (float) when the dispatch was recorded | | `session` | Session id (`""` when unknown) | | `request_snippet` | First 200 chars of the routed request | | `agent`, `skill`, `complexity` | The chosen route | | `health_at_decision` | Picked pair's confidence at decision time; `null` = no weight row or never evaluated (disambiguate with `gate_inputs_present`) | | `n`, `failure` | The other demote-floor inputs, snapshotted with health | | `action` | Step-1.5 health-gate outcome: `keep`, `demote`, or `tiebreak` | | `alternates` | Keys offered as alternatives; `null` when none recorded | | `gate_inputs_present` | `true` = the marker carried a `health=` token; `false`/absent = legacy marker, health never read |

OUTCOME — one per finalized dispatch:

| Field | Meaning | |---|---| | `ts` | Epoch seconds when the outcome was finalized | | `session` | Session id | | `key` | Routing key `{agent}:{skill}` (agent-only `{agent}:` when skill unknown) | | `outcome` | `success`, `failure`, or `neutral` | | `reason` | Short cause (e.g. `tool-errors`, `rejection`, `acceptance`, `neutral-new-topic`); absent in older events | | `routing_relevant` | `true` = a signal the confidence loop acts on; absent = relevance not asserted |

Additive-field history: older lines may lack `n`, `failure`, `action`, `alternates`, `gate_inputs_present`, `reason`, `routing_relevant`. An absent field means "not recorded then", never corruption.

**Step 2: Filter to the user's query**

| User signal | Filter strategy | |-------------|-----------------| | Names an agent or skill | DECISION events where `agent` or `skill` matches, or the name appears in `alternates`; OUTCOME events whose `key` contains it | | "Why did I get routed here" / latest dispatch | Most recent DECISION events (tail of the log), current session first | | Asks about outcome ("did it work", "why failure") | OUTCOME events, joined back to their decisions | | Names a session | Filter both types on `session` | | No specific target | Chronological timeline of the most recent session |

**Step 3: Join out

Read more
Ships withvexjoy-agent

Essays and writing behind this toolkit live at vexjoy.com. VexJoy Agent connects plain-English requests to specialist agents, skills, and workflows. /do selects the knowledge and tools needed for your task.

Get the whole plugin

Other skills on vexjoy-agent.