Skip to content

Tool-call card

In review
Live · web
Large 2.110:24 AM

Lifecycle: running · success (params + output) · error · diff (tab a header, Enter / Space)

file_path
app/src/main/.../net/SseClient.kt
limit
40
Output
// SseClient.kt: the reconnect loop
suspend fun reconnect(attempt: Int) {
delay(nextDelay(attempt))
}
command
./gradlew compileDebugKotlin
Error
e: Backoff.kt:14:18 unresolved reference: Random
> Task :app:compileDebugKotlin FAILED
BUILD FAILED in 3s
file_path
app/src/main/.../net/Backoff.kt
Backoff.kt+2-1
fun nextDelay(attempt: Int): Long =
minOf(15_000, 1_000 shl attempt)
minOf(30_000, 1_000 shl attempt)
.plus(Random.nextLong(250))

Families: the FILLED icon tile tints by tool family (categorical, never the brand cyan)

Copy fired 0 times · tab a card header to expand, tab to its Copy button. The island is live.

// Web: React, consuming @dizyx/nockerl-tokens. (Web is the laggard platform. Spec + live demo,
// not yet exported from @dizyx/nockerl-react; promotion is tracked.)
export function Turn() {
return (
<>
{/* A running shell-fs call: a pulsing dot + elapsed, no body to disclose yet. */}
<ToolCallCard name="$ ./gradlew test" family="shell-fs" status="running" elapsedSeconds={6} icon="terminal" />
{/* A finished Read: collapsible key/value params + a recessed code/text well. */}
<ToolCallCard
name="Read SseClient.kt"
family="shell-fs"
status="success"
elapsedSeconds={0.4}
icon="file"
params={[{ label: 'file_path', value: 'net/SseClient.kt' }, { label: 'limit', value: '40' }]}
output={{ lines: readSnippet }}
/>
{/* An Edit: the output renders as an inline unified diff instead of a code well. */}
<ToolCallCard
name="Edit Backoff.kt"
family="shell-fs"
status="success"
icon="edit"
diff={{ path: 'net/Backoff.kt', lines: editDiff }}
/>
</>
);
}

Harness failure block (a view, no new grammar)

Section titled “Harness failure block (a view, no new grammar)”

Per the WS4 verdict (task 2655d), a harness failure is the whole agent run dying (a crashed session, a gateway 500, a budget kill), bigger than one tool error. It is a thin composition of ratified parts, not a component:

  1. The failure banner. The r5.2-ratified failure grammar (adjudication 2026-07-02, addendum r5.2): an inset error disc, a whisper-red border (the Banner 22% mix, never a red fill), on a lifted solid surface. Title = what died (“Harness crashed”); message = the one-line why.
  2. The evidence well. Whatever the failure left behind, in the part that already owns it: this card’s error output well for a tool-level trace, a CodeBlock for a stack/log excerpt, a DiffViewer for a bad patch.
  3. Recovery actions. The banner’s own right-aligned quiet action (“Retry”, “Open logs”), or for a decision moment the Approval content CTA row.

Stack them in that order in the transcript column: banner first (the verdict), the evidence collapsed beneath (this card’s collapse idiom). Compose; invent nothing: the failure expression must stay byte-identical with the ChatBubble send-failure and the AgentMessage stream-failure, which bind to the same banner grammar.

PropTypeDefaultDescription
name *stringTool name / one-line summary, in the mono font (e.g. Read SseClient.kt, $ ./gradlew test).
family *'shell-fs' | 'agent' | 'scheduling' | 'planning' | 'external' | 'default'Drives the filled icon-tile accent from the categorical family tokens. The family color rides in the leading tile, never a left rail (Law 6), never the brand cyan.
status *'running' | 'success' | 'error'Run state: running → a neutral pulse dot, success → a check, error → a close. All warm + a glyph, never color-alone.
elapsedSecondsnumberWall-clock time in the status chip: %.1fs under 10s, else Ns.
icon *ReactNodeThe family glyph for the icon tile (tinted via currentColor).
paramsToolParam[]Compact key → value call parameters shown first in the expanded body (muted label + strong mono value).
output{ lines: OutLine[]; error?: boolean }Expanded code/text result rendered in the recessed well. error tints it with the error wash.
diff{ path: string; lines: DiffLine[] }Render the result as an inline unified diff (added/removed washes + a +/- gutter) instead of a code well.
defaultOpenbooleanfalseStart expanded. The header is the disclosure (aria-expanded); a body-less card stays static.