ADR-0070: Quiet tool styling in the Telegram view¶
- Status: Accepted
- Date: 2026-10-20
- Related: ADR-0026 (TUI dim tool hints — the semantic precedent), issue #290, issue #253 (result caps)
Context¶
The TUI renders tool hints dim (ADR-0026): tool traffic is machinery, the agent's prose is the conversation. Telegram has no dim attribute — the only de-emphasis its message entities offer are italic (lighter weight), inline code (monospace, reads smaller), spoilers (hidden until tapped) and HTML blockquotes (grey bar, needs a different parse mode).
Today's tool lines are the loudest messages in the chat — bold name +
code block — while the 💬 response body is plain text. Tool traffic is
also the most frequent type, so a remote session reads as machinery.
Two latent bugs live in the same lines: NotifyToolUse ships uncapped
and unchunked (an oversized cliToolArgSummary preview makes the send
silently fail — Telegram's 4096-unit limit), and summaries containing
newlines produce multi-line MarkdownV2 code spans, which parse
unreliably.
Decision¶
Tier 1 — quiet single-line tool messages, staying MarkdownV2:
| Event | Format |
|---|---|
| tool use | ⚙ _Bash_ · \grep -rn foo`(bare⚙ Bash` with no summary) |
| result (ok) | 📤 _Bash_ · \2 matches`` |
| result (error) | ❌ *Bash* error · \exit 1…`` — stays bold; failures are never quietly dimmed |
- The tool name is italic (escMD —
_is active outside code); the summary is an inline code span escaped only per the MarkdownV2 rule for code (\and`— fullescMDwould over-escape-,., … with no purpose and no visible benefit inside code). - Flatten then cap, rune-safe: newlines →
⏎(single line), tool-use preview ≤ 200 runes, result ≤ 497 (the issue-#253 cap). Together with the unchunked-send path this guarantees every tool message stays far under the 4096-unit limit. - Builders are pure (
toolUseMessage,toolResultMessage— mirroringturnStartMessage) and table-tested;NotifyToolUse/NotifyToolResultonly wrap them. The state flip for the busy status line is unaffected.
Unchanged: 🔄 turn notices, 💬 responses, 🔐/❓ asks, the
busy-status line — user-facing messages keep full weight. Empty result
summaries still send nothing (pre-existing rule).
Rejected (for now, revisited on demand)¶
- Tier 2 — spoiler wraps (
||…||) for bulky results: literal "dim", but hidden until tapped; annoys for one-liners. Threshold idea (~80 runes) recorded in issue #290 if wanted later. - Tier 3 — HTML
<blockquote>: loudest "secondary content" cue, but needs a per-message parse mode through the outbound queue and re-derived chunk budgets. Real plumbing; only worth it if Tier 1 does not feel quiet enough. - A
remote_oversight.tool_styleknob: the TUI dims tool hints unconditionally — same precedent; add a knob only if someone asks.
Consequences¶
- The remote chat reads as conversation with tooling as quiet tags; errors stay visually loud. Existing chunking and status-line tests are untouched (no test pinned the old tool strings).
- Tool-event send failures from oversized previews are structurally impossible (cap asserted in tests).