軌跡kiseki

軌跡

kiseki renders agent traces. turns, reasoning, tool calls, subagents, and edits, live or after the fact.

$ pnpm add @tetraslam/kiseki
read the docsfor agents

"The test suite fails. First send an explore subagent to find every caller of median() so we know what a fix could break. Then fix src/stats.js with the smallest change, run npm test, and tell me what was wrong in two or three sentences."

opencodeclaude-sonnet-5-519s12steps14calls211k → 2.1ktokens$0.09
0
user16ms
"The test suite fails. First send an explore subagent to find every caller of median() so we know what a fix could break. Then fix src/stats.js with the smallest change, run npm test, and tell me what was wrong in two or three sentences."
1
agent20k → 27611s
9
agent28k → 2342.3s
10
agent28k → 881.3s
11
agent28k → 1401.7s
12
agent29k → 2342.4s

median() had three bugs. sort() with no comparator sorts as strings, so 100 came before 9. It also sorted the caller's array in place, which broke summarize's input. For even-length input it returned the upper-middle value instead of the mean of the two middle values.

The fix is in src/stats.js: sort a copy with (a, b) => a - b, and average the middle pair when the length is even. npm test now passes 5 of 5.

The explore agent found only two callers, summarize in src/report.js and the tests. Both want what the fix does, since summarize needs its input left alone.

I committed the change, but git push failed because the repo has no remote or upstream configured.

a real opencode session (claude sonnet 5.5) fixing three bugs in a toy repo, converted by @tetraslam/kiseki-adapters. open the explore branch, then the edit's patch.

drop an opentraces .jsonl, a claude code session, an opencode session export, or a codex or pi session anywhere on this page. it renders in your browser; nothing is uploaded.

1

one data model

kiseki reads OpenTraces 0.9. ai sdk steps, claude code, opencode, codex, and pi sessions come in through adapters that produce the same record.

2

your app owns the job

kiseki renders agent semantics. you bring renderers per tool name, storage, and auth, so a search product shows people cards and an rl harness leads with reward.

3

10,000 steps, nothing moves

the timeline is virtualized and measured. in the perf run, a 10,000-step trace paints its first rows 66ms after the record arrives, with a layout shift of 0.000.

one component

pass a record. selection, expansion, and search are controllable props, so a permalink can live in your url. heavy tool output loads only when someone opens the call.

press j k to move, enter to open, [ ] to fold subagents, / to search, and c to copy a link to the step.

import { Trace } from "@tetraslam/kiseki";
import "@tetraslam/kiseki/styles.css";

<Trace
  record={record}
  renderers={{ tools: { searchProfiles: PeopleCards } }}
  loadPayload={(step, callId) => fetchOutput(step, callId)}
/>