From d34496da0be37cd21dd56639028669f10a874d68 Mon Sep 17 00:00:00 2001 From: Jonas H Date: Thu, 11 Jun 2026 09:11:00 +0200 Subject: [PATCH] Document embedded terminal module in CLAUDE.md Co-Authored-By: Claude Fable 5 --- CLAUDE.md | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index 38d6ea2..1b864c4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -16,6 +16,10 @@ src/sse.rs incremental SSE parser; tolerant of chunk splits mid-event/mid-UT src/app.rs Arc> shared state; Tap = one in-flight tapped request, translates SSE events → session Entries (Drop closes it out) src/ui.rs ratatui rendering @ ~30fps; session list + scrollable feed +src/term.rs embedded claude pane: spawns `claude --session-id ` in a + portable-pty routed through the proxy; wezterm-term models the + screen (and answers terminal queries); renderer paints cells + into the ratatui buffer ``` Data flow: proxy task parses SSE chunks → `Tap::handle()` mutates shared state → @@ -30,9 +34,17 @@ UI thread redraws on its own tick (no channel; just the mutex). sends identity encoding we can parse in transit. Don't "fix" that. - Hop-by-hop headers (`content-length`, `transfer-encoding`, etc.) are stripped both directions; hyper re-frames. -- Sessions are keyed by the UUID after `session_` in request `metadata.user_id`. +- Sessions are keyed by the session UUID in request `metadata.user_id` — + Claude Code ≥2.1.x sends a JSON blob with `"session_id":""`, older + builds `user_…_session_`; `proxy::session_key` handles both. Concurrent requests (subagents) share a session but each `Tap` tracks its own current entry index — entries/sessions are append-only, so indices stay stable. +- The embedded pane's session is matched by the `--session-id` UUID we + generate; the tap drives pane behavior: grows it for AskUserQuestion / + ExitPlanMode (sized from the question's option count) before Claude Code + renders the prompt, shrinks when the tool_result echoes back, and schedules + a ctrl-l transcript wipe 400ms after each turn (the pane is prompt-only; + the feed shows the context). - Tool input streams as raw JSON fragments; pretty-printed only on `content_block_stop`. Text re-renders markdown every frame, so partial markdown self-heals. @@ -41,6 +53,15 @@ UI thread redraws on its own tick (no channel; just the mutex). - `tui-markdown` is pinned `=0.3.5`: later versions use `ratatui-core` (0.30 alpha types), incompatible with ratatui 0.29. +- `wezterm-term`/`wezterm-surface` are not on crates.io: pinned to a git rev + of the wezterm monorepo (keep both revs identical). +- The pane's render window crops Claude Code chrome by *position* + (`term.rs`: `BOTTOM_CROP`, start ≥ 2, `PTY_PAD`) — tuned to the current + Claude Code UI; retune there if an update adds/removes chrome rows. +- Keybindings avoid Alt entirely: on layouts like dk_mac_fixed, Alt composes + characters (alt-c = ©) and never reaches the app as a modifier. Pane keys: + F2 toggle, ctrl-↓ focus claude, ctrl-↑ focus feed. `CT_DEBUG_KEYS=1` shows + raw key events in the status bar. - ratatui needs feature `unstable-rendered-line-info` for `Paragraph::line_count` (used for follow/auto-scroll). - reqwest is `default-features = false` + `rustls-tls,stream` — don't enable @@ -59,3 +80,8 @@ UI thread redraws on its own tick (no channel; just the mutex). - Tool results only appear once the *next* request fires; if the session ends right after a tool call, that result is never seen. Output is what Claude Code sends the model (i.e. post-truncation). +- Embedded pane: no bracketed paste or mouse forwarding yet; no scrollback + view (live screen only); shift+enter needs kitty keyboard protocol pushed + on the outer terminal (not done); permission prompts aren't detected for + pane growth (not visible in the API stream — would need a Notification + hook hitting a local control endpoint).