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,
using the literal wire spelling declared beside each engine key in
display-fields, and re-keywording keyword-valued fields. The single inbound
projection channels use — the mirror of ->display.
Read the canonical display fields back off a gateway WIRE event into a form, using the literal wire spelling declared beside each engine key in `display-fields`, and re-keywording keyword-valued fields. The single inbound projection 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.
The canonical engine keys projected by ->display and recovered by <-wire.
The canonical engine keys projected by `->display` and recovered by `<-wire`.
(hide-tool-code? {:keys [error success?] :as form})Should a channel DROP a form's invocation source instead of showing it as a
separate code block? Successful native tools already have a result card, so
their synthesized invocation is redundant. Failed native tools keep source
context. python_execution is different: its program is user-relevant
evidence and remains visible on both success and failure. This is the shared
TUI/channel policy; web mirrors it at the wire boundary.
Should a channel DROP a form's invocation source instead of showing it as a separate code block? Successful native tools already have a result card, so their synthesized invocation is redundant. Failed native tools keep source context. `python_execution` is different: its program is user-relevant evidence and remains visible on both success and failure. This is the shared TUI/channel policy; web mirrors it at the wire boundary.
(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 pending-summary
result-render pending-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>)
A call still RUNNING has no result yet, so the headline falls back to the
tool-authored :pending-summary (shell's $ npm test (running)): the SAME
card, in its awaiting state, rather than a bare unlabeled code band.
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>`)
A call still RUNNING has no result yet, so the headline falls back to the
tool-authored `:pending-summary` (`shell`'s `$ npm test (running)`): the SAME
card, in its awaiting state, rather than a bare unlabeled code band.
`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).
Native tools whose SUBMITTED invocation stays visible while the call is STILL
RUNNING — the command/program itself is the payload a user needs to judge a
long-running op. Every other native tool just spins behind its badge: a 200ms
cat/grep must not flash a bordered code frame with a copy control for
something nobody reads. python_execution additionally keeps its source after
completion (see hide-tool-code?); shell only while it runs, because the
finished command is already carried by its op-card headline.
Native tools whose SUBMITTED invocation stays visible while the call is STILL RUNNING — the command/program itself is the payload a user needs to judge a long-running op. Every other native tool just spins behind its badge: a 200ms `cat`/`grep` must not flash a bordered code frame with a copy control for something nobody reads. `python_execution` additionally keeps its source after completion (see `hide-tool-code?`); `shell` only while it runs, because the finished command is already carried by its op-card headline.
(show-running-tool-code? form)Should a channel show a STILL-RUNNING form's invocation source even though
hide-tool-code? would drop it once the call completes? Only for
running-code-tools (and non-tool forms, which have no op-card to hide
behind) — and never when the tool AUTHORED its own pending card body
(:pending-render): that body already IS the submitted command, rendered as
the card renders it, so the raw invocation beside it would say the same thing
twice in JSON. This is the shared TUI/channel policy; web mirrors it.
Should a channel show a STILL-RUNNING form's invocation source even though `hide-tool-code?` would drop it once the call completes? Only for `running-code-tools` (and non-tool forms, which have no op-card to hide behind) — and never when the tool AUTHORED its own pending card body (`:pending-render`): that body already IS the submitted command, rendered as the card renders it, so the raw invocation beside it would say the same thing twice in JSON. This is the shared TUI/channel policy; web mirrors it.
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.
(with-display-code form)Attach the canonical cached ruff rendering of a form's Python source.
Channels render :display-code verbatim; local callers without it may use
the same formatter. Nested result cards are normalized recursively.
An AUTHORED :display-code is never overwritten: a native tool may render
its own PENDING call (:render-call — shell ships the bash it is about to
run instead of the raw invocation JSON), and that surface, paired with its
:display-language, is the one the channels must paint.
Attach the canonical cached ruff rendering of a form's Python source. Channels render `:display-code` verbatim; local callers without it may use the same formatter. Nested result cards are normalized recursively. An AUTHORED `:display-code` is never overwritten: a native tool may render its own PENDING call (`:render-call` — `shell` ships the bash it is about to run instead of the raw invocation JSON), and that surface, paired with its `:display-language`, is the one the channels must paint.
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 |