The canonical per-form DISPLAY contract — ONE source of truth for the fields a channel reads to render an executed form, live (via the gateway) and restored (via the DB).
Why this exists: the SAME field set used to be hand-listed in ~7 independent
allowlists — the loop chunk, the persisted block, the gateway block.output
wire payload, the gateway→chunk client projection, the live progress form, the
DB-restored form, and the restored display form. A new field was invisible
until every one was edited, and whichever layer forgot it silently dropped the
field (the gateway dropping :tool-color-role so the live badge vanished was
exactly that). Now every layer projects the WHOLE set through ->display
(outbound) / <-wire (inbound, tolerant of the wire's snake_case + stringified
keyword values), so a new display field is a ONE-line change to display-keys
and form-roundtrip-test fails if a boundary stops carrying it.
Transformed fields (:stdout/:error bounded, :silent/:duration_ms
renamed) stay as explicit gateway overrides — they are not carried verbatim, so
they are NOT in this set.
The canonical per-form DISPLAY contract — ONE source of truth for the fields a channel reads to render an executed form, live (via the gateway) and restored (via the DB). Why this exists: the SAME field set used to be hand-listed in ~7 independent allowlists — the loop chunk, the persisted block, the gateway `block.output` wire payload, the gateway→chunk client projection, the live progress form, the DB-restored form, and the restored display form. A new field was invisible until every one was edited, and whichever layer forgot it silently dropped the field (the gateway dropping `:tool-color-role` so the live badge vanished was exactly that). Now every layer projects the WHOLE set through `->display` (outbound) / `<-wire` (inbound, tolerant of the wire's snake_case + stringified keyword values), so a new display field is a ONE-line change to `display-keys` and `form-roundtrip-test` fails if a boundary stops carrying it. Transformed fields (`:stdout`/`:error` bounded, `:silent`/`:duration_ms` renamed) stay as explicit gateway overrides — they are not carried verbatim, so they are NOT in this set.
(->display m)Project the canonical display fields off a source map (loop chunk/block, a restored row) — the ONE projection every form builder + the gateway uses instead of hand-listing keys. Drops nils so a merge never stamps empty keys.
Project the canonical display fields off a source map (loop chunk/block, a restored row) — the ONE projection every form builder + the gateway uses instead of hand-listing keys. Drops nils so a merge never stamps empty keys.
(<-wire event)Read the canonical display fields back off a gateway WIRE event into a form,
tolerant of snake_case keys and re-keywording the keyword-valued fields. The
single inbound projection the channels use — the mirror of ->display.
Read the canonical display fields back off a gateway WIRE event into a form, tolerant of snake_case keys and re-keywording the keyword-valued fields. The single inbound projection the channels use — the mirror of `->display`.
(coalesce-forms forms)Merge each maximal run of ADJACENT, successful coalescable native op-cards into
a single card. cat/patch coalesce only for the SAME file; format_code
coalesces adjacent per-file acks into one roll-up across files. Every other
form passes through untouched. The ONE projection both channels apply before
rendering an iteration's forms, so repeated tool acks never render as a stack
of look-alike sibling bubbles. Always returns a vector.
Merge each maximal run of ADJACENT, successful coalescable native op-cards into a single card. `cat`/`patch` coalesce only for the SAME file; `format_code` coalesces adjacent per-file acks into one roll-up across files. Every other form passes through untouched. The ONE projection both channels apply before rendering an iteration's forms, so repeated tool acks never render as a stack of look-alike sibling bubbles. Always returns a vector.
Every field carried VERBATIM from the loop to a channel to render a form — the
complete passthrough set, NOT the handful the gateway computes/renames itself
(:stdout/:error are bounded, :silent/:duration_ms are derived; those
stay explicit gateway overrides). Add a new verbatim display field HERE and
->display/<-wire flow it across every boundary.
Grouped: the source the model wrote, the result surfaces (raw + the pre-rendered op-card), the native-tool badge identity (label + colour), the per-form display projections, the tool-call linkage, and the repair/timeout flags channels surface.
Every field carried VERBATIM from the loop to a channel to render a form — the complete passthrough set, NOT the handful the gateway computes/renames itself (`:stdout`/`:error` are bounded, `:silent`/`:duration_ms` are derived; those stay explicit gateway overrides). Add a new verbatim display field HERE and `->display`/`<-wire` flow it across every boundary. Grouped: the source the model wrote, the result surfaces (raw + the pre-rendered op-card), the native-tool badge identity (label + colour), the per-form display projections, the tool-call linkage, and the repair/timeout flags channels surface.
(hide-tool-code? {:keys [error success?] :as form})Should a channel DROP a form's synthesized invocation source (the name(args)
code block) instead of showing it as code? YES for a SUCCESSFUL native tool
call (cat/rg/patch/…) that is NOT python_execution: the op-card
(result-card) already says what ran, so the source is redundant chrome.
python_execution — the model's OWN program — always keeps its code; an
ERRORED form keeps it too (the inline error needs the surrounding source).
The ONE predicate the TUI and web both consult so the code-chrome decision
can't drift between channels.
Should a channel DROP a form's synthesized invocation source (the `name(args)` code block) instead of showing it as code? YES for a SUCCESSFUL native tool call (cat/rg/patch/…) that is NOT `python_execution`: the op-card (`result-card`) already says what ran, so the source is redundant chrome. `python_execution` — the model's OWN program — always keeps its code; an ERRORED form keeps it too (the inline error needs the surrounding source). The ONE predicate the TUI and web both consult so the code-chrome decision can't drift between channels.
(native-tool-form? {tool-name :vis/tool-name})True when form is a NATIVE tool call (cat/rg/patch/…): it carries a
:vis/tool-name and therefore renders as an op-card via result-card.
True when `form` is a NATIVE tool call (cat/rg/patch/…): it carries a `:vis/tool-name` and therefore renders as an op-card via `result-card`.
(result-card {:keys [tool-color-role result-summary result-render]
tool-name :vis/tool-name})Canonical tool-result CARD descriptor — the ONE place the op-card / collapse
decision is made, so the TUI and web AGREE on tool?/label/colour/summary/
collapsible instead of each re-deriving it from the raw form. Given an executed
form map, returns the op-card shape for a NATIVE TOOL result:
{:tool? true
:label "RG" — op-card badge label (tool-label)
:color-role :tool-color/search — badge colour role (keyword-normalized,
since a JSON wire hop stringifies it)
:summary "5 hits in 1 file" — the HEADLINE (:result-summary), nil
when the tool authored none
:body "…markdown…" — the detail body (:result-render), nil
for a summary-only tool (move/delete)
:collapsible? true} — true ⇔ there's a body to fold under
the summary (a chevron/<details>)
nil for a NON-tool form (no :vis/tool-name) — its result rendering stays
channel-specific (raw value / stdout). The badge is whatever the tool's
:summary already produced; no first-line-of-body heuristic.
Canonical tool-result CARD descriptor — the ONE place the op-card / collapse
decision is made, so the TUI and web AGREE on `tool?`/label/colour/summary/
collapsible instead of each re-deriving it from the raw form. Given an executed
form map, returns the op-card shape for a NATIVE TOOL result:
{:tool? true
:label "RG" — op-card badge label (`tool-label`)
:color-role :tool-color/search — badge colour role (keyword-normalized,
since a JSON wire hop stringifies it)
:summary "5 hits in 1 file" — the HEADLINE (`:result-summary`), nil
when the tool authored none
:body "…markdown…" — the detail body (`:result-render`), nil
for a summary-only tool (move/delete)
:collapsible? true} — true ⇔ there's a body to fold under
the summary (a chevron/`<details>`)
`nil` for a NON-tool form (no `:vis/tool-name`) — its result rendering stays
channel-specific (raw value / stdout). The badge is whatever the tool's
`:summary` already produced; no first-line-of-body heuristic.(result-cards form)The op-card descriptor(s) a form renders — the ONE place a channel asks "what cards does this form show?" so the TUI and web never re-derive it differently.
A python block that print()ed several tool results carries a :cards vector of
canonical mini-forms; each becomes its OWN op-card via result-card. Any other
form yields its single result-card (or none). Always a vector — channels just
iterate. Empty when the form has no tool card at all (plain value / stdout).
The op-card descriptor(s) a form renders — the ONE place a channel asks "what cards does this form show?" so the TUI and web never re-derive it differently. A python block that print()ed several tool results carries a `:cards` vector of canonical mini-forms; each becomes its OWN op-card via `result-card`. Any other form yields its single `result-card` (or none). Always a vector — channels just iterate. Empty when the form has no tool card at all (plain value / stdout).
The canonical set of native-tool op-card BADGE colour roles — the ONE list both
channels colour against (TUI maps each to a lanterna fg, the web to a --tool-*
CSS var). Hand-maintained per-channel maps were free to drift; a guard test in
each channel asserts its map covers every role here, so a new role can't be
added in one channel and silently forgotten in the other.
The canonical set of native-tool op-card BADGE colour roles — the ONE list both channels colour against (TUI maps each to a lanterna fg, the web to a `--tool-*` CSS var). Hand-maintained per-channel maps were free to drift; a guard test in each channel asserts its map covers every role here, so a new role can't be added in one channel and silently forgotten in the other.
(tool-label wire-name)The op-card badge LABEL for a native tool's wire name: the name uppercased,
except the few label-overrides rename. ONE place both channels derive it from
so the TUI badge and the web label never drift. nil for a non-tool form.
The op-card badge LABEL for a native tool's wire name: the name uppercased, except the few `label-overrides` rename. ONE place both channels derive it from so the TUI badge and the web label never drift. nil for a non-tool form.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |