Skip to main content

Trajectory observability

A query on its own says little about whether a search was any good. Jevlin carries enough of the agent's context with each search that the platform can group one task's searches and show what the agent was doing when it asked.

Searches, turns, threads and trajectories​

Jevlin records at four levels, each inside the next. The bottom two are what the router sees on every request; the top two are what the platform assembles from them.

levelwhat it iswhere it comes from
SearchOne request to the router and its answer. On the platform a search is a trace: the query, the tier, and a receipt per provider with its status, latency, result count and cost.Every jevlin search call. The call_id names it.
TurnOne exchange with the agent: what you asked, what the agent did, including every search it made, and what it concluded.The agent's hooks: the turn_id the searches carry, and the turn end when it is on.
ThreadOne conversation in an agent, across all its turns, context compactions and subagents. The agent calls it a session; the platform calls it a thread, the same word LangSmith and Braintrust use.The session_id the hooks keep in a lineage file; a subagent's thread also names its parent.
TrajectoryA thread read back as a path: each turn in order, with the assistant text that led to each search, the searches themselves, what came back, and what the turn concluded.The platform, by projecting a thread's searches and turn ends onto one timeline.

A trace answers "was this search any good?": open it and see which providers answered, which timed out, and what each returned. A trajectory answers "what was the agent doing, and did the search move it along?": the same search appears there once, in place, between the text the agent wrote before it and what it did after. Nothing is nested in that view; the turns and their searches are laid out flat, in the order they happened, so you can read the thread as the path the agent took.

Two more words appear in the trace fields below. The window is which context window of the thread a search was made in, counted up at each compaction, so searches before and after a compaction still belong to one thread. The seq is a call counter, so two searches in one turn keep their order.

The trace​

fieldcarries
harnessWhich agent: claude-code, codex, cursor, and so on.
session_id, turn_id, call_idThe agent's ids, hashed with SHA-256 before they leave the machine. session_id is the thread.
parent_session_idOn a subagent's search only: the hashed session of the agent that started it.
windowWhich context window of the session, after compactions.
seqA call counter.
historyThe assistant text just before the search, scrubbed of secrets, last 32 KiB. Codex and Hermes send none.
host_metaAgent-specific metadata.

The real ids never leave the machine; the router sees only the hashes, so it can group searches without learning which conversation they came from. The trace lists every field and every scrub rule.

Lineage files​

The hooks keep a lineage file per workspace, and in Cursor per conversation, under ~/.jevlin/sessions. Each search reads it to learn which session, window and turn it belongs to, so the searches of one task line up even across context compactions and subagents. Only the agent that wrote a file reads it, so a second agent in a subdirectory never sends the first one's narration. Pi reads its ids back from the session Pi itself saved, so a resumed session keeps its place.

Without a hook, a search still carries a per-shell identity, hashed with a key that never leaves state/, so even a bare terminal's searches group together.

What the platform shows​

Each search appears on platform.jevlin.ai twice, at two zoom levels.

Traces shows one search. The query, the tier, the provider the router chose, and a receipt per provider: whether it answered, timed out or is still pending, how long it took, how many results it returned, and what it cost. Totals give the results, the unique pages, the wall time and the cost of the search.

Trajectories shows one thread. One row per thread lists what the agent asked and what came back, with the turn count, the search count, latency, cost and when it was last active. Open one and you read the thread as a path: each turn, the assistant text that led to each search as its input, the pages that came back as its output, and the searches, cost, latency and turn id as attributes. A search that found nothing, or a provider that degraded, is marked on the row.

That is the whole point of carrying the trace: a list of query strings tells you what was asked, and a trajectory tells you why, and whether the answer moved the task along.

The turn end​

The trace carries what the assistant wrote before a search. With [miner] turn_end = true, the agent's end-of-turn hook also sends what the turn concluded: the final message, what you asked, the tools called by name, duration and outcome, the model and the token counts. Only for turns in which a search was served, and never a tool's input or output. See The turn end.

Turning it off​

export JEVLIN_TRACE=off

Sends no trace and no turn end. Searches work the same without them, and are metered the same. See What leaves the machine.